<?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>DEV Community: AlvBarros</title>
    <description>The latest articles on DEV Community by AlvBarros (@alvbarros).</description>
    <link>https://dev.to/alvbarros</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%2F1139155%2F807c74cd-28aa-4fb7-90d7-a0f22181c256.png</url>
      <title>DEV Community: AlvBarros</title>
      <link>https://dev.to/alvbarros</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alvbarros"/>
    <language>en</language>
    <item>
      <title>Brief Introduction to CNNs</title>
      <dc:creator>AlvBarros</dc:creator>
      <pubDate>Wed, 21 Jan 2026 13:32:43 +0000</pubDate>
      <link>https://dev.to/alvbarros/brief-introduction-to-cnns-1g57</link>
      <guid>https://dev.to/alvbarros/brief-introduction-to-cnns-1g57</guid>
      <description>&lt;p&gt;&lt;em&gt;This article is heavily based on &lt;a href="https://arxiv.org/abs/1511.08458" rel="noopener noreferrer"&gt;An Introduction to Convolutional Neural Networks&lt;/a&gt; by Keiron O'Shea and Ryan Nash.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let's begin by discussing some background knowledge. &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%2Fgupypiueuojailu6d0oc.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%2Fgupypiueuojailu6d0oc.png" alt="Venn diagram of fields inside Artificial Intelligence" width="696" height="678"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Source: &lt;a href="https://www.researchgate.net/publication/359100075_Application_of_Artificial_Intelligence_in_Lung_Cancer" rel="noopener noreferrer"&gt;Application of Artificial Intelligence in Lung Cancer&lt;/a&gt;. A Venn diagram of fields inside Artificial Intelligence.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deep Learning
&lt;/h2&gt;

&lt;p&gt;As the diagram shows, deep learning is a subset of machine learning as a whole, and its key distinction to other types of machine learning is the &lt;strong&gt;automatic feature extraction&lt;/strong&gt; and &lt;strong&gt;data dependency&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Feature engineering:&lt;/strong&gt; Automatically learns features from raw data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data:&lt;/strong&gt; Needs way more data than traditional ML.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance:&lt;/strong&gt; Slower to train and requires significant computing power (GPUs), but achieves higher accuracy in complex tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interpretability:&lt;/strong&gt; Often considered a "black box" due to its complexity and automatic feature extraction.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Neural Networks
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Artificial Neural Networks&lt;/strong&gt; are a high number of interconnected computational nodes (referred to as neurons), of which work entwine in a distributed fashion to collectively learn from the input in order to optimize its final output.&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%2Fcx3bx1g0u98vhpqpvm0s.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%2Fcx3bx1g0u98vhpqpvm0s.png" alt="FNN" width="800" height="545"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Source: &lt;a href="https://arxiv.org/abs/1511.08458" rel="noopener noreferrer"&gt;An Introduction to Convolutional Neural Networks&lt;/a&gt;. A three-layered feedforward neural network, comprised of a input layer, a hidden layer and an output layer.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Convolutional Neural Networks
&lt;/h2&gt;

&lt;p&gt;The main notable difference between CNNs and traditional ANNs is that CNNs are primarily used in the field of pattern recognition within images.&lt;/p&gt;

&lt;p&gt;The layers within the CNN are comprised of neurons organized into three dimensions: the spatial dimesionality of the input (&lt;strong&gt;height&lt;/strong&gt; and &lt;strong&gt;width&lt;/strong&gt;) and the &lt;strong&gt;depth&lt;/strong&gt;. This "depth" does not refer to the total number of layers within the ANN, but the third dimension of an activation volume.&lt;/p&gt;

&lt;h3&gt;
  
  
  Overall architecture
&lt;/h3&gt;

&lt;p&gt;CNNs are comprised of three types of layers: &lt;strong&gt;convolutional&lt;/strong&gt; layers, &lt;strong&gt;pooling&lt;/strong&gt; layers and &lt;strong&gt;fully-connected&lt;/strong&gt; layers.&lt;/p&gt;

&lt;p&gt;Take for example this simplified CNN architecture for MNIST classification.&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%2F6kbjv3u8hpsc6rtwiq16.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%2F6kbjv3u8hpsc6rtwiq16.png" alt="Simplified CNN architecture of 5 layers" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://arxiv.org/abs/1511.08458" rel="noopener noreferrer"&gt;An Introduction to Convolutional Neural Networks&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;strong&gt;input layer&lt;/strong&gt; will hold the pixel values of the image. These can be RGB colors.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;convolutional layer&lt;/strong&gt; will determine the output of neurons of which are connected to local regions of the input through the calculation of the scalar product between their weights and the region connected to the input volume. The &lt;strong&gt;rectified linear unit&lt;/strong&gt; (commonly shortened to &lt;strong&gt;ReLu&lt;/strong&gt;) aims to apply an "elementwise" activation function such as sigmoid to the output of the activation produced by the previous layer.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;pooling layer&lt;/strong&gt; will then simply perform &lt;strong&gt;downsampling&lt;/strong&gt; along the spatial dimensionality of the given input, reducing the image size and in turn the amount of parameters.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;fully connected layers&lt;/strong&gt; will then perform the same duties found in standard neural networks and attempt to produce class scores from the activations. It is also suggested that ReLu may be used between these layers as to improve performance.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Convolutional layer
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Convolution&lt;/strong&gt; is a mathematical operation that measures how one function overlaps another across space or time.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;neural networks&lt;/strong&gt;, it means &lt;em&gt;sliding&lt;/em&gt; a small filter over the data to systematically detect local patterns (such as edges, textures, or shapes). &lt;/p&gt;

&lt;p&gt;Here's a &lt;a href="https://www.youtube.com/watch?v=KuXjwB4LzSA" rel="noopener noreferrer"&gt;great video by 3Blue1Brown&lt;/a&gt; that goes more in-depth and offers some visualization.&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%2F7itldcwudn8whcya4cgr.gif" 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%2F7itldcwudn8whcya4cgr.gif" alt="Kernel animation" width="760" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice how a matrix goes through every pixel of the original image.&lt;br&gt;
The convolution in the animation is just averaging out every neighboring pixel, so it results in a "blur" effect. Consider that every pixel is a matrix of &lt;strong&gt;red, green and blue&lt;/strong&gt; values (RGB) from 0 to 255. So, for example, a completely red pixel would be &lt;strong&gt;[255, 0, 0]&lt;/strong&gt;. The kernel is a matrix of 3x3 filled with &lt;strong&gt;1/9&lt;/strong&gt;, so that you average the pixel's neighbors. I heavily encourage you to watch the video so it makes more sense.&lt;/p&gt;

&lt;h4&gt;
  
  
  Kernel
&lt;/h4&gt;

&lt;p&gt;The "filter" or the matrix of 1/9's in the example above is called a &lt;strong&gt;kernel&lt;/strong&gt;. They are usually small in spatial dimensionality, but spread along the entire image.&lt;/p&gt;

&lt;p&gt;When the data hits a convolutional layer, the layer &lt;strong&gt;convolves&lt;/strong&gt; each filter across the spatial dimensionality of the input to produce a 2D activation map.&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%2F6rmhl229fe8alud09dwf.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%2F6rmhl229fe8alud09dwf.png" alt="Kernel example" width="800" height="259"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Source: &lt;a href="https://arxiv.org/abs/1511.08458" rel="noopener noreferrer"&gt;An Introduction to Convolutional Neural Networks&lt;/a&gt;. A visual representation of a convolutional layer. The center element of the kernel is placed over the input vector (image), of which is then calculated and replaced with a weighted sum of itself and any nearby pixels.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Training neural networks on inputs such as images results in models of which are too big to train effectively. Consider an image of 800 height and 600 width. This would mean &lt;em&gt;800 x 600 = 480.000&lt;/em&gt; pixels. Bear in mind pixels are RGB matrixes as we explained earlier, so it would mean &lt;em&gt;480.000 x 3 = 1.440.000&lt;/em&gt;. So just for this image, the number of weights on a single neuron would be almost 1.5 million, and these networks usually way more than one neuron.&lt;/p&gt;

&lt;p&gt;To mitigate this, the convolutional layer must be connected to small regions of the input, referred to as the &lt;strong&gt;receptive field size&lt;/strong&gt; of the neuron. To visualize this, if the input of the network is an image of size &lt;strong&gt;64 x 64 x 3&lt;/strong&gt; and we set the receptive field size as &lt;strong&gt;6 x 6&lt;/strong&gt;, we would have a total of &lt;strong&gt;108 weights&lt;/strong&gt; on each neuron in the layer. To put this into perspective, a standard neuron seen in other forms of neural networks would contain &lt;strong&gt;12.288 weights&lt;/strong&gt; each.&lt;/p&gt;

&lt;h4&gt;
  
  
  Optimization
&lt;/h4&gt;

&lt;p&gt;Convolutional layers are also able to significantly reduce the complexity of the model through three hyperparameters: &lt;strong&gt;depth, stride and zero-padding&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Depth:&lt;/strong&gt; The depth produced can be manually set through the number of neurons within the layer. This can be seen with other forms of neural networks, where all of the neurons in the hidden layer are connected to every single neuron beforehand. Reducing this can significantly minimize the total number of neurons, but it can also significantly reduce the pattern recognition capabilities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stride:&lt;/strong&gt; You can think of this as the amount of "steps" we take when applying the convolution kernel. A stride of one would mean that every pixel would be put through the convolution. A stride of two, would mean that 1 in every 2 pixels would be put, so one would be skipped.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Zero-padding:&lt;/strong&gt; It's the simple process of padding the border of the input, and is an effective method to give further control as to the dimensionality of the output volumes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With these, we can calculate the size of the 2D output of the convolutional layer.&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%2Faxqe0xa0o4fc9gjxc6ua.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%2Faxqe0xa0o4fc9gjxc6ua.png" alt="Formula to calculate the output size" width="226" height="94"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Source: &lt;a href="https://arxiv.org/abs/1511.08458" rel="noopener noreferrer"&gt;An Introduction to Convolutional Neural Networks&lt;/a&gt;. V represents the input volume size (height x width x depth), R represents the receptive field size, Z is the amount of zero padding set and S referring to the stride. If the calculated result is not an integer, then the stride has been incorrectly set.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parameter sharing&lt;/strong&gt;, the idea that the kernel is the same for the entire image, works on the assumption that if one region feature is useful to compute at a set spatial region, then it is likely to be useful in another region. &lt;/p&gt;

&lt;h3&gt;
  
  
  Pooling layer
&lt;/h3&gt;

&lt;p&gt;The objective is to gradually reduce the dimensionality of the representation.&lt;/p&gt;

&lt;p&gt;It operates over each activation map in the input, and scales its dimensionality using the "MAX" function. In most CNNs, these come in the form of &lt;strong&gt;max-pooling layers&lt;/strong&gt; with kernels of a dimensionality of &lt;strong&gt;2 x 2&lt;/strong&gt; applied with a stride of 2 along the spatial dimensions of the input. This scales the activation map down to 25% of the original size - whilst maintaining the depth volume to its standard size.&lt;/p&gt;

&lt;p&gt;Due to its destructive nature, there are only two generally observed methods of max-pooling. The one mentioned previously, which allows the layer to extend through the entirety of the image, or &lt;strong&gt;overlapping pooling&lt;/strong&gt; where the stride is set to 2 with a kernel size set to 3. Having a kernel size of the pooling layer above 3 will usually greatly decrease the performance of the model.&lt;/p&gt;

&lt;p&gt;It's important to note that beyond max-pooling, some CNNs may contain &lt;strong&gt;general pooling&lt;/strong&gt;. These layers are comprised of pooling neurons that are able to perform a multitude of common operations including L1/L2-normalisation, and average pooling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fully-connected layer
&lt;/h3&gt;

&lt;p&gt;This layer contains neurons of which are directly connected to the neurons in the two adjacent layers, without being connected to any layers within them. This is analogous to the way that neurons are arranged in traditional forms of neural networks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recipes
&lt;/h2&gt;

&lt;p&gt;Despite the relatively small number of layers required for a CNN, there is no set way of formulating a CNN architecture. That being said, they follow a common architecture.&lt;/p&gt;

&lt;p&gt;This common architecture is of convolutional layers stacked, followed by pooling layers in a repeated manner before feeding forward to fully-connected layers, as show in the Overall architecture section.&lt;/p&gt;

&lt;p&gt;Another way is to stack two convolutional layers before each pooling layer, as illustrated below. This is strongly recommended as stacking multiple convolutional layers allows for more complex features of the input vector to be selected.&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%2Fo3ryk8j557m4mwxfn4ce.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%2Fo3ryk8j557m4mwxfn4ce.png" alt="Another way to stack" width="800" height="205"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Source: &lt;a href="https://arxiv.org/abs/1511.08458" rel="noopener noreferrer"&gt;An Introduction to Convolutional Neural Networks&lt;/a&gt;. A common form of CNN architecture in which convolutional layers are stacked between ReLus continuousl before being passed through the pooling layer, before going between one or many fully connected ReLus.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Also, it is advised to split up large convolutional layers into smaller ones in order to reduce the amount of computational complexity within a given layer.&lt;/p&gt;

&lt;p&gt;For example, imagine you were to stack three layers on top of each other with a receptive field of 3 x 3. Each neuron on the first layer would have a 3 x 3 view of the input vector. The second layer neuron, however, is acting on the output of the first layer. So, even though the kernel size can also be of 3 x 3, effectively the second neuron is also depending on the first layer. Removing the overlapping pixels and assuming a stride of 1, We have a 5 x 5 dimensionality (since one column overlaps). If you do it again for a third layer, effectively the receptive field is now of 7 x 7, and so on.&lt;/p&gt;

&lt;p&gt;The input layer should be recursively divisible by two. Common numbers include 32 x 32, 64 x 64, 96 x 96, 128 x 128 and 224 x 224.&lt;/p&gt;

&lt;p&gt;With small filters, set stride to one and make use of zero-padding as to ensure that the convolutional layers do not reconfigure any of the dimensionality of the input. The amount of zero-padding to be used should be calculated by taking one away from the receptive field size and dividing by two.&lt;/p&gt;

&lt;p&gt;CNNs can be horrendously resource-heavy. An example of this problem could be in filtering a large image (anything over 128 x 128 could be considered large), so if the input is 227 x 227 (as seen with ImageNet) and we're filtering with 64 kernels each with a zero padding, then the result will bee three activation vectors of size 227 x 227 x 64 - which calculates to roughly 10 million activations - or an enormous 70 megabytes of memory per image.&lt;/p&gt;

&lt;p&gt;In this case there are two options.&lt;/p&gt;

&lt;p&gt;First, you can reduce the spatial dimensionality of the input images by resizing the raw imags to something a little less heavy.&lt;/p&gt;

&lt;p&gt;Alternatively, you can go against everything we stated earlier and opt for larger filter sizes with a larger stride (2, as opposed to 1).&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;CNNs differ to other forms of neural networks in that instead of focusing on the entirety of the problem domain, knowledge about the specific type of input is exploited. This in turn allows for a much simpler network architecture to be set up.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>ai</category>
      <category>beginners</category>
      <category>learning</category>
    </item>
    <item>
      <title>Gradient Descent from Scratch</title>
      <dc:creator>AlvBarros</dc:creator>
      <pubDate>Sat, 09 Aug 2025 20:12:27 +0000</pubDate>
      <link>https://dev.to/alvbarros/linear-regression-with-gradient-descent-39p1</link>
      <guid>https://dev.to/alvbarros/linear-regression-with-gradient-descent-39p1</guid>
      <description>&lt;p&gt;In your quest to learn machine learning, this is probably the first and simplest prediction model you will learn. Each one of these words have a meaning! Let's break it down:&lt;/p&gt;

&lt;h2&gt;
  
  
  Linear Regression
&lt;/h2&gt;

&lt;p&gt;Linear regression attempts to model the relationship between &lt;strong&gt;two variables&lt;/strong&gt; by fitting a &lt;strong&gt;linear&lt;/strong&gt; equation to observer data.&lt;/p&gt;

&lt;p&gt;So, if you have two variables and they have a relationship you can use this to create a prediction model.&lt;/p&gt;

&lt;p&gt;The classic example is &lt;strong&gt;Housing Prices&lt;/strong&gt;. The bigger the house is, the pricier it gets. So one variable could be &lt;em&gt;Area Size&lt;/em&gt; and the other &lt;em&gt;Price&lt;/em&gt;. We can use Linear Regression to predict the price of a house based on its size!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;&lt;br&gt;
Of course, houses have way more variables than that.&lt;br&gt;
Things like the number of bedrooms, number of bathrooms, the neighborhood and city, year of construction, and many other parameters influence the price.&lt;br&gt;
This is &lt;strong&gt;not&lt;/strong&gt; the best model for this prediction - it is just the simplest!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When we say &lt;em&gt;linear&lt;/em&gt;, what we mean is that it is going to fit in a &lt;strong&gt;linear equation&lt;/strong&gt;. On one axis you have the house area, and on the other the price!&lt;/p&gt;

&lt;p&gt;Imagine that, by the end, we have a mathematical function that you just have to provide the house area and we get the price. Something like this:&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%2Fkildqp1tjdqjiztwdul1.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%2Fkildqp1tjdqjiztwdul1.png" alt="Y = aX + b" width="216" height="171"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Y is the house price&lt;/li&gt;
&lt;li&gt;X is the house area&lt;/li&gt;
&lt;li&gt;a is the slope of the line&lt;/li&gt;
&lt;li&gt;b is the intercept (value of Y when X=0)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In code it will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;predict_house_price&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;area&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;

&lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;predict_house_price&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Seems easy!
&lt;/h2&gt;

&lt;p&gt;Calm down. We have to understand another thing: &lt;strong&gt;cost functions!!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's begin with an easy example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consider that a house with &lt;strong&gt;area 50m²&lt;/strong&gt; is priced at &lt;strong&gt;US$ 100.000&lt;/strong&gt;. &lt;em&gt;we wish!&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Now consider that another house with &lt;strong&gt;area 75m²&lt;/strong&gt; is priced at &lt;strong&gt;US$ 125.000&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;And last, another one that has &lt;strong&gt;area 100m²&lt;/strong&gt; is priced at &lt;strong&gt;US$ 150.000&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is easy: the function would be &lt;code&gt;Price = Area * 1000 + 50.000&lt;/code&gt;. This is the graph:&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%2F609q4z1u4jj2qc0crk16.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%2F609q4z1u4jj2qc0crk16.png" alt="Easy example of Linear equation" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But data in the real world isn't as easy, and house prices are not influenced only by its area. For example, houses with bigger areas could mean more bedrooms and more bathrooms, or it could mean a pool! These details are what complicates this prediction. Consider the following graph:&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%2F5m0iwiamwilqemtb7dxw.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%2F5m0iwiamwilqemtb7dxw.png" alt="Not so simple example of Linear equation" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now a simple straight line can't really match and predict correctly every single dot in the graph. &lt;/p&gt;

&lt;p&gt;This is where we get more technical.&lt;/p&gt;

&lt;p&gt;We can try and quantify the &lt;strong&gt;accuracy of this function&lt;/strong&gt; by measuring the distance of every dot to the line. This is the &lt;strong&gt;cost function&lt;/strong&gt;. The function for the line is called &lt;strong&gt;hypothesis&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost Function
&lt;/h2&gt;

&lt;p&gt;It is the average difference of all the results of the hypothesis with inputs from X and the actual output Y.&lt;/p&gt;

&lt;p&gt;This function will give us the average accuracy to every prediction we have with the straight line.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For this article, we'll implement a type of &lt;strong&gt;Mean Squared Error&lt;/strong&gt;, but keep in mind there are other types of cost functions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For every X we'll do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run the hypothesis &amp;gt; &lt;em&gt;(Y = aX + b)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Get the difference &amp;gt; &lt;em&gt;predictedY - actualY&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Square it &amp;gt; &lt;em&gt;difference*difference&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Add it to all errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the end, we divide by the amount of data points (e.g. the number of houses/prices) in order to get the average. You can also do it by half of the average in cases where we're going to use gradient descent (more on this later).&lt;/p&gt;

&lt;p&gt;In Python, this is what it would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cost_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;              &lt;span class="c1"&gt;# Target variable
&lt;/span&gt;    &lt;span class="n"&gt;predictions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;# Model predictions
&lt;/span&gt;    &lt;span class="n"&gt;m&lt;/span&gt;               &lt;span class="c1"&gt;# Number of training examples
&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        Calculate the cost function for linear regression.
        J(theta) = (1/(2*m)) * sum(errors^2)
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;sumErrorsSquared&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&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;m&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;sumErrorsSquared&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;predictions&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="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;y&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="o"&gt;**&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;

    &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sumErrorsSquared&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We square the difference for two reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Negative errors cancel out positive ones&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes we predict the value Y as being higher than the real Y, and other times we predict Y as being lower. By squaring it, we make sure it does not matter if the difference is positive or negative.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Penalize bigger mistakes more&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Small errors become huge errors, so the accuracy gets a bigger hit and small variations in accuracy matter more.&lt;/p&gt;

&lt;p&gt;Okay, but why you're telling me about this?&lt;/p&gt;

&lt;h2&gt;
  
  
  Gradient Descent
&lt;/h2&gt;

&lt;p&gt;Gradient descent is a method for &lt;strong&gt;unconstrained mathematical optimization&lt;/strong&gt;. It is an &lt;strong&gt;iterative&lt;/strong&gt; algorithm to &lt;strong&gt;minimize a function&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Can you see where we're going with this? &lt;/p&gt;

&lt;p&gt;We're going to start out with a random arbitrary hypothesis, run our cost function, and then run gradient descent in order to minimize the value of this cost function. This will increase the accuracy of our hypothesis!&lt;/p&gt;

&lt;p&gt;Gradient descent works by the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It begins by having arbitrary values&lt;/li&gt;
&lt;li&gt;It calculates the loss (cost function)&lt;/li&gt;
&lt;li&gt;Decides which way to go - in this case, &lt;strong&gt;descent&lt;/strong&gt; means it wants to minimize the value&lt;/li&gt;
&lt;li&gt;Take another in this direction, and the step size is the &lt;strong&gt;learning rate&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Calculates again until it runs out of steps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you &lt;em&gt;(for some reason?)&lt;/em&gt; want the mathematical formula:&lt;br&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%2Fp5wowhvh3nm17iiiigd2.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%2Fp5wowhvh3nm17iiiigd2.png" alt="Gradient Descent formula" width="800" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This basically means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;repeat until convergence&lt;/em&gt; means that we'll repeat the following steps until the values of the parameters stop changing significantly (convergence is reached).&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;θⱼ&lt;/em&gt; is the parameter being updated in every repetition&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;α&lt;/em&gt; is the &lt;strong&gt;learning rate&lt;/strong&gt;. A small positive value that controls the size of the update step.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;∂&lt;/em&gt; is a partial derivative. It means we're taking the derivative of a function with respect to one variable, while keeping the others constant.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;∂/∂θⱼ J(θ₀, θ₁)&lt;/em&gt; is the partial derivative of the cost function J(θ₀, θ₁) with respect to θⱼ. In other words, how much the cost would change if we nudged θⱼ slightly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I find code easier to understand, so here it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;gradient_descent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                              &lt;span class="c1"&gt;# Input features
&lt;/span&gt;    &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                              &lt;span class="c1"&gt;# Target variable
&lt;/span&gt;    &lt;span class="n"&gt;alpha&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                          &lt;span class="c1"&gt;# Learning rate
&lt;/span&gt;    &lt;span class="n"&gt;steps&lt;/span&gt;                           &lt;span class="c1"&gt;# Number of iterations
&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Perform gradient descent to find the best fitting line for linear regression.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="n"&gt;theta0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="n"&gt;theta1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&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;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="ow"&gt;in&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;steps&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;theta0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;theta1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;gradient_descent_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;theta0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;theta1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;alpha&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;theta0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;theta1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now for each step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;gradient_descent_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;# Input features
&lt;/span&gt;        &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;# Target variable
&lt;/span&gt;        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;# Number of training examples
&lt;/span&gt;        &lt;span class="n"&gt;thetas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;# Tuple of (theta0, theta1)
&lt;/span&gt;        &lt;span class="n"&gt;alpha&lt;/span&gt;       &lt;span class="c1"&gt;# Learning rate
&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        Perform a single step of gradient descent.
        theta0 = theta0 - alpha * (1/m) * sum(errors)
        theta1 = theta1 - alpha * (1/m) * sum(errors * X)
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;theta0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;theta1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;thetas&lt;/span&gt;

    &lt;span class="n"&gt;sumHypothesisMinusValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;sumHypothesisMinusValueTimesX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&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;m&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;hypothesis_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hypothesis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;theta0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;theta1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;X&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;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hypothesis_value&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;y&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;sumHypothesisMinusValue&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;
        &lt;span class="n"&gt;sumHypothesisMinusValueTimesX&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;X&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;theta0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;theta0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alpha&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="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sumHypothesisMinusValue&lt;/span&gt;
    &lt;span class="n"&gt;theta1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;theta1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alpha&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="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sumHypothesisMinusValueTimesX&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;theta0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;theta1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real world example
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://github.com/AlvBarros/santos_housing_prices" rel="noopener noreferrer"&gt;this repository&lt;/a&gt;, I have a script that gets the data from a local real estate broker in my hometown &lt;em&gt;(along with every code shared in this article!)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This results in a bunch of real-world data from houses in the market at the time of recording.&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%2F3l56vxm6h1p92lrm5n4a.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%2F3l56vxm6h1p92lrm5n4a.png" alt="First rows in my data source" width="800" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, we begin by importing this data:&lt;br&gt;
&lt;/p&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;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;area&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When working with data, it is always good to run some data processing and cleaning.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, we remove the outliers
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;remove_outliers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;3.0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;z_scores&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;mean&lt;/span&gt; &lt;span class="o"&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;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&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;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;std&lt;/span&gt; &lt;span class="o"&gt;=&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;v&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;mean&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&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;values&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;

    &lt;span class="n"&gt;x_z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x_mean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x_std&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;z_scores&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;y_z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_mean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_std&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;z_scores&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;filtered&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="n"&gt;xi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;yi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;xi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zi_x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zi_y&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x_z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_z&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;yi&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xi&lt;/span&gt;&lt;span class="p"&gt;)]]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zi_x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zi_y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;filtered&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;All data removed as outliers!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;X_filtered&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_filtered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;filtered&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;X_filtered&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_filtered&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, because the values are big (upwards of hundred of thousands) we can encounter some errors in python (especially since we're squaring some values). &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To fix this, we scale the numbers down.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;minmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;x_min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x_max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&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="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;y_min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&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="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;X_scaled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;xi&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x_min&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x_max&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x_min&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;xi&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;y_scaled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;yi&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;y_min&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_max&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;y_min&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;yi&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;X_scaled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_scaled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x_min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x_max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_max&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the data is cleaned, we can run gradient descent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;theta0_scaled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;theta1_scaled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;gradient_descent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;X_scaled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;y_scaled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;alpha&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;alpha&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;steps&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;theta0&lt;/code&gt; and &lt;code&gt;theta1&lt;/code&gt; mentioned in the code are the &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; we discussed previously.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We must scale them back to normal if we want to use these values in a prediction manner.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scaling the thetas back:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;unscale_thetas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;theta0_scaled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;theta1_scaled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x_min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x_max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_max&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;x_range&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x_max&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x_min&lt;/span&gt;
    &lt;span class="n"&gt;y_range&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y_max&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;y_min&lt;/span&gt;

    &lt;span class="n"&gt;theta1_unscaled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_range&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;x_range&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;theta1_scaled&lt;/span&gt;
    &lt;span class="n"&gt;theta0_unscaled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y_min&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y_range&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;theta0_scaled&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;theta1_scaled&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x_min&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;x_range&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;theta0_unscaled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;theta1_unscaled&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;And that's it!&lt;/strong&gt;  🎉🍾👏&lt;/p&gt;

&lt;p&gt;This is an example of plot I got running &lt;a href="https://github.com/AlvBarros/santos_housing_prices" rel="noopener noreferrer"&gt;my code&lt;/a&gt;:&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%2Fb0orw1jqfidil3y8j7du.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%2Fb0orw1jqfidil3y8j7du.png" alt="Plot" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And these are the thetas (&lt;em&gt;a&lt;/em&gt; and &lt;em&gt;b&lt;/em&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;theta0: 104727.42003321546&lt;/li&gt;
&lt;li&gt;theta1: 7699.98612392038&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, if you want to implement the method &lt;code&gt;predict_house_price&lt;/code&gt; we have in the beggining of this article:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;predict_house_price&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;theta0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;104727.42003321546&lt;/span&gt;
    &lt;span class="n"&gt;theta1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;7699.98612392038&lt;/span&gt;

    &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;theta0&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;theta1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;area&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Take a moment to look at &lt;a href="https://github.com/AlvBarros/santos_housing_prices" rel="noopener noreferrer"&gt;my repository&lt;/a&gt; if you want to run this code in your own dataset.&lt;/p&gt;

&lt;p&gt;Keep in mind, this process is super iterative and a different amount of steps and a bigger or smaller learning rate may provide better or worse results.&lt;/p&gt;

&lt;p&gt;In the end, house prices cannot be predicted with only one variable, so this is more of a thought experiment than a real model for prediction.&lt;/p&gt;

&lt;p&gt;Keep learning!&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>python</category>
      <category>datascience</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>The Kth factor of N - an O(sqrt n) algorithm</title>
      <dc:creator>AlvBarros</dc:creator>
      <pubDate>Tue, 17 Dec 2024 22:34:43 +0000</pubDate>
      <link>https://dev.to/alvbarros/the-kth-factor-of-n-an-osqrt-n-algorithm-4ce0</link>
      <guid>https://dev.to/alvbarros/the-kth-factor-of-n-an-osqrt-n-algorithm-4ce0</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Recently I wrote the post &lt;a href="https://dev.to/alvbarros/learn-big-o-notation-once-and-for-all-hm9"&gt;Learn Big O Notation once and for all&lt;/a&gt;. In that post I go over all of the types of Big O time notation that is available at the &lt;a href="https://www.bigocheatsheet.com/" rel="noopener noreferrer"&gt;Big-O cheatsheet&lt;/a&gt;. And I did not think there would be any more time notations possible outside of those seven. &lt;/p&gt;

&lt;p&gt;As if the universe itself was humbling me and mocking my ignorance, I encountered a &lt;a href="https://leetcode.com/problems/the-kth-factor-of-n/" rel="noopener noreferrer"&gt;LeetCode problem&lt;/a&gt; with a solution of &lt;strong&gt;O(√n)&lt;/strong&gt; time.  Which could be translated to &lt;strong&gt;O(N^1/2)&lt;/strong&gt;, if you're crazy.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;You are given two positive integers &lt;code&gt;n&lt;/code&gt; and &lt;code&gt;k&lt;/code&gt;. A &lt;a href="https://en.wikipedia.org/wiki/Divisor" rel="noopener noreferrer"&gt;factor&lt;/a&gt; of an integer &lt;code&gt;n&lt;/code&gt; is defined as an integer &lt;code&gt;i&lt;/code&gt; where &lt;code&gt;n % i == 0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Consider a list of all factors of &lt;code&gt;n&lt;/code&gt; sorted in &lt;strong&gt;ascending order&lt;/strong&gt;, return the &lt;code&gt;k&lt;/code&gt;th factor in this list or return &lt;code&gt;-1&lt;/code&gt; if &lt;code&gt;n&lt;/code&gt; has less than &lt;code&gt;k&lt;/code&gt; factors.&lt;/p&gt;

&lt;h2&gt;
  
  
  The obvious solution
&lt;/h2&gt;

&lt;p&gt;Well, if you're like me your first thought was to go through every number from 1 to &lt;code&gt;n&lt;/code&gt;, check if it is a factor, and if it is in the desired &lt;code&gt;k&lt;/code&gt; index, return it.&lt;/p&gt;

&lt;p&gt;The code looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;getkthFactorOfN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&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;n&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&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="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is all fine and dandy, but it is &lt;em&gt;"only"&lt;/em&gt; &lt;strong&gt;O(n)&lt;/strong&gt;. After all, there is only one loop and it goes up to &lt;code&gt;n + 1&lt;/code&gt;.&lt;br&gt;
Every other operation is discarded when considering the time notation.&lt;/p&gt;

&lt;p&gt;But, my friend, there's a catch.&lt;/p&gt;
&lt;h2&gt;
  
  
  Understanding factors
&lt;/h2&gt;

&lt;p&gt;If you think about it, factors are "mirrored" after a certain point.&lt;/p&gt;

&lt;p&gt;Take, for example, the number &lt;code&gt;81&lt;/code&gt;. Its factors are &lt;code&gt;[1, 3, 9, 27]&lt;/code&gt;, where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 * 81 = 81&lt;/li&gt;
&lt;li&gt;3 * 27 = 81&lt;/li&gt;
&lt;li&gt;9 *  9 = 81&lt;/li&gt;
&lt;li&gt;27 * 3 = 81&lt;/li&gt;
&lt;li&gt;81 * 1 = 81&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you don't count the number &lt;code&gt;9&lt;/code&gt;, The operations are simply repeated and flipped. If you divide &lt;code&gt;n&lt;/code&gt; by one of its factors, you get another factor.&lt;br&gt;
Expect the square root of &lt;code&gt;n&lt;/code&gt;, where it is itself squared (duh).&lt;/p&gt;

&lt;p&gt;Armed with this knowledge, we now know that we don't need to iterate through the loop up to &lt;code&gt;n&lt;/code&gt; times (with &lt;code&gt;range(1, n + 1)&lt;/code&gt;), but simply up to &lt;code&gt;math.sqrt(n)&lt;/code&gt;. After that, we've got every factor we need!&lt;/p&gt;
&lt;h2&gt;
  
  
  The not-so-obvious solution
&lt;/h2&gt;

&lt;p&gt;Now that we have everything we need, we need to transform this loop from &lt;code&gt;1 -&amp;gt; n&lt;/code&gt; to &lt;code&gt;1 -&amp;gt; sqrt n&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I'll just throw the code here and we'll go over the lines one by one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;getkthFactorOfN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;factors_asc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;factors_desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;n&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;n&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&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="n"&gt;factors_asc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&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;factors_desc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&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;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&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;factors_asc&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;factors_asc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&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;k&lt;/span&gt; &lt;span class="o"&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;factors_asc&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;k&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&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;factors_desc&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;factors_desc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Oof, it's way more complex. Let's break it down:&lt;/p&gt;

&lt;p&gt;First, we initialize &lt;code&gt;i = 1&lt;/code&gt;. This variable will be used as the "number we're currently at" while searching for factors.&lt;/p&gt;

&lt;p&gt;Second, we'll create two arrays: &lt;code&gt;factors_asc&lt;/code&gt; and &lt;code&gt;factors_desc&lt;/code&gt;. The magic here is that we are going to add factors to &lt;code&gt;factors_asc&lt;/code&gt; - they're named like this because they'll be automatically in ascending order.&lt;br&gt;
Whenever we add something to &lt;code&gt;factors_asc&lt;/code&gt;, we'll divide &lt;code&gt;n&lt;/code&gt; by it and add it to &lt;code&gt;factors_desc&lt;/code&gt;. Similar logic here; they'll be conveniently added in descending order.&lt;/p&gt;

&lt;p&gt;Then, we begin our loop. Here I've changed it to be &lt;code&gt;while i * i &amp;lt;= n&lt;/code&gt;, since we stop when we hit the root of &lt;code&gt;n&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We begin by checking if the current number is a factor (&lt;code&gt;n % i == 0&lt;/code&gt;). If so, we can append it to our &lt;code&gt;factors_asc&lt;/code&gt; array.&lt;/p&gt;

&lt;p&gt;Next, we get the "reverse factor" of &lt;code&gt;i&lt;/code&gt;. We can do this by checking if &lt;code&gt;i != n // i&lt;/code&gt;, or in other words, if it is not the root. This is because the root must not be duplicated in both arrays. If it isn't, we get the reversed factor by running &lt;code&gt;n // i&lt;/code&gt; and appending the result in &lt;code&gt;factors_desc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After that, we add 1 to &lt;code&gt;i&lt;/code&gt; and continue our loop.&lt;/p&gt;

&lt;p&gt;After the loop is done, we must have every factorial we need.&lt;/p&gt;

&lt;p&gt;We begin by checking if &lt;code&gt;k&lt;/code&gt; is in the first half including the root (which can be interpreted as the middle) with &lt;code&gt;if k &amp;lt;= len(factors_asc)&lt;/code&gt;. If so, get the index from this array (remember: arrays begin at zero!).&lt;/p&gt;

&lt;p&gt;If not, we must subtract the amount of factors found from &lt;code&gt;k&lt;/code&gt; and check again - with &lt;code&gt;k -= len(factors_asc)&lt;/code&gt; and &lt;code&gt;if k &amp;lt;= len(factors_desc)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;k&lt;/code&gt; is inside &lt;code&gt;factors_desc&lt;/code&gt;, get its value with &lt;code&gt;factors_desk[-k]&lt;/code&gt; (from last to first).&lt;/p&gt;

&lt;p&gt;If all fails, return &lt;code&gt;-1&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The curve
&lt;/h2&gt;

&lt;p&gt;If you're wondering where in the curves graph it lands, it would be between &lt;strong&gt;O(n)&lt;/strong&gt; and &lt;strong&gt;O(log n)&lt;/strong&gt;, being better than the former and worse than the latter. Here's a graph:&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%2Fur1gc2pmlegtg48onupc.jpeg" 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%2Fur1gc2pmlegtg48onupc.jpeg" alt="The square root function's shape" width="622" height="296"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Available at &lt;a href="https://mathspace.co/textbooks/syllabuses/Syllabus-410/topics/Topic-7286/subtopics/Subtopic-97289/?activeTab=theory" rel="noopener noreferrer"&gt;Mathspace&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This was a ride to uncover and research. Thank you so much for reading up to this point.&lt;/p&gt;

&lt;p&gt;If you want to be more optimized, you can create &lt;code&gt;factors_asc_len&lt;/code&gt; and &lt;code&gt;factors_desc_len&lt;/code&gt; variables and add &lt;code&gt;+1&lt;/code&gt; every time you append a value to these arrays, so that the method &lt;code&gt;len()&lt;/code&gt; doesn't have to be called, since this method is &lt;strong&gt;O(n)&lt;/strong&gt; so it can impact time notation.&lt;/p&gt;

&lt;p&gt;Good luck in your studies and until next time!&lt;/p&gt;

</description>
      <category>interview</category>
      <category>beginners</category>
      <category>algorithms</category>
      <category>python</category>
    </item>
    <item>
      <title>Learn Big O Notation once and for all</title>
      <dc:creator>AlvBarros</dc:creator>
      <pubDate>Tue, 12 Nov 2024 23:01:12 +0000</pubDate>
      <link>https://dev.to/alvbarros/learn-big-o-notation-once-and-for-all-hm9</link>
      <guid>https://dev.to/alvbarros/learn-big-o-notation-once-and-for-all-hm9</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Recently I was doing a job interview to a position that I really wanted in a very cool company, and one of the steps was the dreaded code interview where we solve LeetCode problems live.&lt;/p&gt;

&lt;p&gt;I got the solution, and when asked the big O function for my solution, I answered correctly, but I was very confused and probably stumbled my way into it by simply counting the loops.&lt;/p&gt;

&lt;p&gt;In order to not fail anymore job interviews in the future, I'm revisiting this topic some years after first learning about it in college.&lt;/p&gt;

&lt;p&gt;The main objective behind this post is to provide a quick summary and a refresher for me to read before a coding interview. While I learn by writing, it is also important to store this somewhere I can always revisit when I need. And hey, maybe it can work for you too.&lt;/p&gt;

&lt;p&gt;Big thanks to &lt;a href="https://www.youtube.com/channel/UC_mYaQAE6-71rjSN6CeCA-g" rel="noopener noreferrer"&gt;NeetCode&lt;/a&gt; for providing so much material and teaching all of this stuff for free.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Big O time complexity?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;In computer science, big O notation is used to classify algorithms according to how their run time or space requirements grow as the input size grows. [...] [It] characterizes functions according to their growth rates: different functions with the same asymptotic growth rate may be represented using the same O notation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Source: Wikipedia&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Or, in other words, it's a way to analyze the amount of time of our algorithm takes to run as the input grows. &lt;strong&gt;O&lt;/strong&gt; is meant to be the whole operation, and &lt;strong&gt;n&lt;/strong&gt; the input.&lt;/p&gt;

&lt;p&gt;Let's look at some examples and it will make more sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  O(n) - Sure, give me an example
&lt;/h2&gt;

&lt;p&gt;Perhaps the easiest example to understand is of O(n), where the growth rate is linear.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Given an unsorted array &lt;strong&gt;n&lt;/strong&gt;, write a function that will return the biggest value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To solve this, we need to go through every item in the array &lt;strong&gt;n&lt;/strong&gt; and store it whenever we find a value bigger than the previous found.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&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="mi"&gt;4&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="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&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;3&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="c1"&gt;# Initialize the array of n
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_max_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Initialize the maximum value with the first element of the array
&lt;/span&gt;    &lt;span class="n"&gt;max_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&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="c1"&gt;# Iterate through the array to find the maximum value
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;arr&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;num&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;max_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;max_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;max_value&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;find_max_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# Output: 9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The previous algorithm will always run through every item inside &lt;strong&gt;n&lt;/strong&gt; at least once - it has to, because the array is unsorted.&lt;/p&gt;

&lt;p&gt;Because of this, we say this algorithm has time complexity of &lt;strong&gt;O(n)&lt;/strong&gt;, because as the array size (n) grows, the runtime grows in a linear fashion.&lt;/p&gt;

&lt;p&gt;It also does not care about the non-constant attributes of your algorithm. Imagine that your algorithm iterates through every item in your &lt;strong&gt;n&lt;/strong&gt; exactly twice, resulting in your time complexity of &lt;strong&gt;O(2n)&lt;/strong&gt;. We simplify it by saying it is O(n), because the priority of the Big O notation is to &lt;strong&gt;convey the shape of the growth in run time&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  O(1) - First and only exception
&lt;/h2&gt;

&lt;p&gt;After telling you that we shouldn't care about non-constant values in the notation, We have to discuss the &lt;strong&gt;O(1)&lt;/strong&gt;, where the &lt;strong&gt;n&lt;/strong&gt; is not even present in this classification. It is perhaps the most desirable rate, where the time does not grow with the input, staying constant. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Given a non-empty array, return the first element.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&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="mi"&gt;4&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="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&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;3&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="c1"&gt;# Initialize the array of n
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;first_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Return the first element of the array
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arr&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;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;first_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# Output: 3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because we don't actually iterate through any items in the array, the notation for this operation would be &lt;strong&gt;O(1)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Some other examples of this include appending items to an array, removing (&lt;code&gt;pop&lt;/code&gt;), or when using Hash maps (or Dictionaries) where we simply lookup using an index - like the algorithm above.&lt;/p&gt;

&lt;h2&gt;
  
  
  O(n^2) - This seems easy enough
&lt;/h2&gt;

&lt;p&gt;The simplest case for this notation is when you have &lt;strong&gt;nested loops&lt;/strong&gt;, or a two-dimensional array and you have to go through them to find what you're looking for.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Given a number of sides in a dice, calculate every possible combination when using two dices of the given size
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;dice_combinations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sides&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Initialize combinations array
&lt;/span&gt;    &lt;span class="n"&gt;combinations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="c1"&gt;# Iterate through first side
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&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;sides&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="c1"&gt;# Add every combination possible
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&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;sides&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;combinations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;combinations&lt;/span&gt;

&lt;span class="n"&gt;sides&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;  &lt;span class="c1"&gt;# Example for a 6-sided dice
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;dice_combinations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sides&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# Output: An array with 36 items (6 * 6)
# [(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5), (5, 6), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6)]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But what if the dice have different sides?&lt;/p&gt;

&lt;h2&gt;
  
  
  O(n*m) - Okay, now you're just adding letters
&lt;/h2&gt;

&lt;p&gt;If instead you had to calculate the possible combinations using two dice of different sides, they would work as follows.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Given two numbers of sides in a dice, calculate every possible combination when rolling these two dices.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;two_dice_combinations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sides1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sides2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Initialize combinations array
&lt;/span&gt;    &lt;span class="n"&gt;combinations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="c1"&gt;# Iterate through first side
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&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;sides1&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="c1"&gt;# Add every combination possible
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&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;sides2&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;combinations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;combinations&lt;/span&gt;

&lt;span class="n"&gt;sides1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;  &lt;span class="c1"&gt;# Example for a 6-sided dice
&lt;/span&gt;&lt;span class="n"&gt;sides2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;  &lt;span class="c1"&gt;# Example for an 8-sided dice
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;two_dice_combinations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sides1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sides2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# Output: An array with 48 items (6 * 8)
# [(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (4, 7), (4, 8), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5), (5, 6), (5, 7), (5, 8), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6), (6, 7), (6, 8)]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep in mind that these can work indefinitely. You can have an &lt;strong&gt;O(n^3)&lt;/strong&gt; algorithm if we had three dice, or even &lt;strong&gt;O(n^5)&lt;/strong&gt; - math does not impose a limit.&lt;/p&gt;

&lt;h2&gt;
  
  
  O(log n) - What?
&lt;/h2&gt;

&lt;p&gt;Most people don't even understand what &lt;em&gt;log&lt;/em&gt; means, and simply memorize that this notation is used when doing some sort of &lt;strong&gt;binary search&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is the case when for every iteration of the loop, we divide the loop in half for the next iteration. The &lt;strong&gt;log n&lt;/strong&gt; part then becomes &lt;strong&gt;how many times can we divide n by 2 to get the result&lt;/strong&gt; - which is kind of the definition of this log notation when the base is 2.&lt;/p&gt;

&lt;p&gt;When working with &lt;strong&gt;binary threes&lt;/strong&gt; we have to traverse the nodes, and on each node we have to make a decision - go "left" or go "right". This is already splitting the amount of operations in half since we're only going into one direction (don't mind that the nodes may have a different amount of child nodes).&lt;/p&gt;

&lt;p&gt;This is one of the best algorithms since the run time grows very slowly. For really big input sizes, the time is basically a flat line.&lt;/p&gt;

&lt;p&gt;The most common example of O(log n) is when we're doing a &lt;strong&gt;binary search&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I won't get into too much detail, but basically a binary search can be used when we have a &lt;strong&gt;sorted array&lt;/strong&gt; where we want to find the index of a specific value.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Given a sorted array, find the index of a target value
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;binary_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Initialize the left and right pointers as the first and last
&lt;/span&gt;    &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&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="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="c1"&gt;# Continue searching while the left pointer is less than or equal to the right pointer
&lt;/span&gt;    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Calculate the middle index
&lt;/span&gt;        &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;right&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="c1"&gt;# Check if the middle element is the target
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt;
        &lt;span class="c1"&gt;# If the middle element is less than the target, adjust the left pointer
&lt;/span&gt;        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="c1"&gt;# If the middle element is greater than the target, adjust the right pointer
&lt;/span&gt;        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="c1"&gt;# Return -1 if the target is not found in the array
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="c1"&gt;# Example usage:
&lt;/span&gt;&lt;span class="n"&gt;sorted_array&lt;/span&gt; &lt;span class="o"&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&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;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;binary_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sorted_array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# Output: 6 - sorted_array[6] == 7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the loop is not in the familiar &lt;code&gt;for i in range(1, n)&lt;/code&gt;, but rather the middle between the &lt;code&gt;left&lt;/code&gt; and &lt;code&gt;right&lt;/code&gt; indexes.&lt;/p&gt;

&lt;h2&gt;
  
  
  O(n log n) - Now you're just making stuff up
&lt;/h2&gt;

&lt;p&gt;The only reason this is here is because it is very hard to intuitively figure this out.&lt;/p&gt;

&lt;p&gt;This notation is commonly found in sorting algorithms and in fact is the most common for built-in sorting functions in modern languages.&lt;/p&gt;

&lt;p&gt;Take, for example, the &lt;strong&gt;Merge Sort&lt;/strong&gt;. Just so we do not get into too much detail, it basically works by dividing the array into two halves recursively (log n divisions) and then merges the halves back together in linear time (O(n) for each merge). By combining these two steps, we have &lt;strong&gt;O(n * log n)&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Given an unsorted array, sort it by using merge sort.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;merge_sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&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;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;

    &lt;span class="c1"&gt;# Find the middle point and divide the array into two halves
&lt;/span&gt;    &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&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;arr&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="n"&gt;left_half&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;right_half&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;

    &lt;span class="c1"&gt;# Recursively sort the two halves
&lt;/span&gt;    &lt;span class="n"&gt;left_sorted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;merge_sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left_half&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;right_sorted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;merge_sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;right_half&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Merge the sorted halves
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left_sorted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right_sorted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;sorted_array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;left_index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right_index&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="mi"&gt;0&lt;/span&gt;

    &lt;span class="c1"&gt;# Merge the two arrays while maintaining order
&lt;/span&gt;    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;left_index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;right_index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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;right&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;left&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;left_index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;right_index&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="n"&gt;sorted_array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;left_index&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;left_index&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;sorted_array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;right_index&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;right_index&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="c1"&gt;# Append any remaining elements from the left or right array
&lt;/span&gt;    &lt;span class="n"&gt;sorted_array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;left_index&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
    &lt;span class="n"&gt;sorted_array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;right_index&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sorted_array&lt;/span&gt;

&lt;span class="c1"&gt;# Example usage:
&lt;/span&gt;&lt;span class="n"&gt;unsorted_array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&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="mi"&gt;4&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="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&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;3&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;merge_sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unsorted_array&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# Output: [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see in the code above that every time &lt;code&gt;merge_sort&lt;/code&gt; is called, it ends by calling &lt;code&gt;merge&lt;/code&gt;. And every time merge_sort is called, it also calls itself twice, one for each half of the array.&lt;/p&gt;

&lt;h2&gt;
  
  
  O(2^n) - I should have seen it coming
&lt;/h2&gt;

&lt;p&gt;This notation is usually found when we have a recursion algorithm that branches out in two ways.&lt;/p&gt;

&lt;p&gt;We can easily see these complexities in &lt;strong&gt;bubble sort&lt;/strong&gt;, but as we can't talk about algorithms without talking about Fibonacci, let's finally do it. But remember - there are more efficient ways to solve this problem.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Given an index, find the number in the Fibonacci sequence.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&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;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
    &lt;span class="n"&gt;branch1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&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;branch2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;branch1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;branch2&lt;/span&gt;

&lt;span class="c1"&gt;# Example usage:
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fibonacci&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="c1"&gt;# Output: 5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is clear in the implementation above that two branches are created for every iteration of the recursive loop.&lt;/p&gt;

&lt;p&gt;For example, for &lt;code&gt;n = 5&lt;/code&gt;, we would have &lt;code&gt;fibonacci(4)&lt;/code&gt; and &lt;code&gt;fibonacci(3)&lt;/code&gt; be called, which would generate &lt;code&gt;fibonacci(3)&lt;/code&gt; &lt;strong&gt;again&lt;/strong&gt; (we have not implemented memoization in the above algorithm), &lt;code&gt;fibonacci(2)&lt;/code&gt; &lt;strong&gt;twice&lt;/strong&gt; and &lt;code&gt;fibonacci(1)&lt;/code&gt;. You can visualize it as an "upside down binary tree", where the height of the tree is &lt;strong&gt;n&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Theoretically we could have any number being raised to the power of &lt;strong&gt;n&lt;/strong&gt;, such as &lt;strong&gt;O(3^n)&lt;/strong&gt; and &lt;strong&gt;O(5^n)&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  O(n!) - Make it end, please!
&lt;/h2&gt;

&lt;p&gt;If you don't know what the &lt;strong&gt;!&lt;/strong&gt; means, we simply multiply the number by every number - 1 until we get to 1 (which we can ignore).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For example:&lt;br&gt;
5! = 5 * 4 * 3 * 2 = 120&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can think of this as an algorithm that for every iteration, remove an item and run again. It mainly comes up in permutations or, perhaps more famously, in the Traveling Salesman Problem.&lt;/p&gt;

&lt;p&gt;For this one, I won't be adding any piece of code since this can get very complicated and this is extremely rare anyways, because if you have an algorithm of &lt;strong&gt;O(n!)&lt;/strong&gt; you most definitely don't have the optimal solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  So there you have it!
&lt;/h2&gt;

&lt;p&gt;You can refer to the graph below to see how the algorithms compare. The vertical axis means the number of operations (or also the time) and the horizontal axis means the amount of elements (or the value of &lt;strong&gt;n&lt;/strong&gt;). Special thanks to Eric Rowell for the cheatsheet!&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%2Fr59g1uzesoygr0wq5nuc.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%2Fr59g1uzesoygr0wq5nuc.png" alt="Big-O Complexity Chart" width="800" height="547"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Available at &lt;a href="https://www.bigocheatsheet.com/" rel="noopener noreferrer"&gt;https://www.bigocheatsheet.com/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I hope you've found this post useful, and good luck in your future studies! 🤞&lt;/p&gt;

&lt;h2&gt;
  
  
  EDIT: O(sqrt n)
&lt;/h2&gt;

&lt;p&gt;After this was written I've encountered a LeetCode problem that has a solution O(sqrt n). Here's another blogpost if you're curious: &lt;a href="https://dev.to/alvbarros/the-kth-factor-of-n-an-osqrt-n-algorithm-4ce0"&gt;The Kth factor of N - an O(sqrt n) algorithm&lt;/a&gt;&lt;/p&gt;

</description>
      <category>interview</category>
      <category>beginners</category>
      <category>algorithms</category>
      <category>python</category>
    </item>
    <item>
      <title>Toxicity in Tweets using a BERT model</title>
      <dc:creator>AlvBarros</dc:creator>
      <pubDate>Thu, 11 Apr 2024 12:41:47 +0000</pubDate>
      <link>https://dev.to/alvbarros/toxicity-in-tweets-using-a-bert-model-37in</link>
      <guid>https://dev.to/alvbarros/toxicity-in-tweets-using-a-bert-model-37in</guid>
      <description>&lt;h2&gt;
  
  
  The goal
&lt;/h2&gt;

&lt;p&gt;The goal for this project is to create a model that can accurately classify some piece of text into &lt;strong&gt;Toxic or not&lt;/strong&gt;. Basically, if &lt;strong&gt;toxicity = 1&lt;/strong&gt; or &lt;strong&gt;0&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is a very simple problem to solve, all you need is a database of texts that are toxic and not, and then you can train your model on it.&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%2Fv4iog92vp9rhhady7gkl.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%2Fv4iog92vp9rhhady7gkl.png" alt="Basic diagram that shows that the text " width="800" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The dataset
&lt;/h2&gt;

&lt;p&gt;The competition specifies that the model must be able to predict texts written in &lt;strong&gt;Brazilian Portuguese&lt;/strong&gt;, so the dataset is in Portuguese as well.&lt;/p&gt;

&lt;p&gt;The dataset is based on &lt;a href="https://github.com/JAugusto97/ToLD-Br" rel="noopener noreferrer"&gt;ToLD-Br&lt;/a&gt;, which is a huge dataset of tweets &lt;del&gt;(or is it Xeets now?)&lt;/del&gt; that contains some additional info such as a classification if the text contains &lt;strong&gt;homophobia, obscenity, insults, racism, misogyny and xenophobia&lt;/strong&gt;. The dataset for the competition, however, is a simple &lt;strong&gt;toxicity&lt;/strong&gt; column.&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%2Fv0tdeqix9s3q4x30xf18.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%2Fv0tdeqix9s3q4x30xf18.png" alt="A small snapshot of the dataset in a table manner" width="800" height="685"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;On the left, the 'Text' column contains the tweet in question, and the 'Toxicity' column if the text is either toxic or not (1 or 0)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Classification problem
&lt;/h2&gt;

&lt;p&gt;Whenever you think about classification, your first guess would be that you need some kind of neural network.&lt;/p&gt;

&lt;p&gt;As you may guess from the title of the article, &lt;strong&gt;BERT&lt;/strong&gt; was chosen since it is more recent, it's built in a neural network architecture that uses &lt;strong&gt;transformers&lt;/strong&gt;, which is perfect for Natural Language Processing (NLP).&lt;/p&gt;

&lt;h3&gt;
  
  
  How does BERT work?
&lt;/h3&gt;

&lt;p&gt;Recurrent and convolutional neural networks use sequential computation to generate predictions. They can predict which word will follow a sequence of given words once trained on huge datasets - this behavior is nicknamed &lt;strong&gt;unidirectional&lt;/strong&gt; algorithm.&lt;/p&gt;

&lt;p&gt;BERT, however, has a mechanism called &lt;em&gt;self-attention&lt;/em&gt;, which can do this prediction based on the words that precede &lt;strong&gt;but also that follow&lt;/strong&gt;, or in other words, a &lt;strong&gt;bi-directional&lt;/strong&gt; algorithm.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: &lt;a href="https://www.datacamp.com/blog/what-is-bert-an-intro-to-bert-models" rel="noopener noreferrer"&gt;Javier Canales Luna @ DataCamp&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The training
&lt;/h2&gt;

&lt;p&gt;First of all, the training data must be cleaned up so that less characters need to be processed by our model. There's some theory on what characters matter and what don't, but I've decided on this final function for &lt;code&gt;format_text&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;format_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Convert text to lowercase
&lt;/span&gt;    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;# Remove words that begin with @ such as tagging @user
&lt;/span&gt;    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@\w+&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Remove words that begin with # such as #happy
&lt;/span&gt;    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\b#\w+\b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Remove URLs
&lt;/span&gt;    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http\S+&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Remove punctuation and emojis
&lt;/span&gt;    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;[^\w\s]&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Remove stop words
&lt;/span&gt;    &lt;span class="n"&gt;pt_stp_words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stopwords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;words&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;portuguese&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&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;word&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pt_stp_words&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="c1"&gt;# Remove double spaces
&lt;/span&gt;    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\s+&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The comments are all self-explanatory. All but one: &lt;strong&gt;stopwords&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are stopwords?
&lt;/h3&gt;

&lt;p&gt;Stopwords are words that are very frequently found in phrases but they don't add very significant meaning.&lt;/p&gt;

&lt;p&gt;Such words are "i", "my", "myself", "you", "your". More words can be found &lt;a href="https://gist.github.com/sebleier/554280" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For this project, however, I've used stopwords for the Portuguese language available in the &lt;code&gt;nltk.corpus&lt;/code&gt; package.&lt;/p&gt;

&lt;h2&gt;
  
  
  The model
&lt;/h2&gt;

&lt;p&gt;Now, to be used in our model we'll create a &lt;code&gt;TextClassificationDataset&lt;/code&gt; class that'll handle the storing and encoding of our texts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TextClassificationDataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Dataset&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;texts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;texts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;texts&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;labels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;labels&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tokenizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;

    &lt;span class="k"&gt;def&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;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;texts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__getitem__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;texts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;encoding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;return_tensors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pt&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;max_length&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;truncation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;input_ids&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;input_ids&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;attention_mask&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;attention_mask&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;label&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tensor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;label&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;We begin by defining that this class is a PyTorch Dataset.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;__init__&lt;/code&gt; method takes the arguments &lt;code&gt;texts&lt;/code&gt; and &lt;code&gt;labels&lt;/code&gt;, which are the values in the train dataset in the format of a list. So, for example, the row #3 would have the content of the tweet at &lt;code&gt;texts[2]&lt;/code&gt; and the classification at &lt;code&gt;labels[2]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The argument &lt;code&gt;tokenizer&lt;/code&gt; is used to convert the texts into a format that the model can understand - since it cannot understand straight text.&lt;/li&gt;
&lt;li&gt;The argument &lt;code&gt;max_length&lt;/code&gt; is used to limit the length of the tokenized sequences.&lt;/li&gt;
&lt;li&gt;The method &lt;code&gt;__len__&lt;/code&gt; returns the number of samples.&lt;/li&gt;
&lt;li&gt;The method &lt;code&gt;__getitem__&lt;/code&gt; is used to retrieve the specific item given an index &lt;code&gt;idx&lt;/code&gt;. This will retrieve the item from the lists of &lt;code&gt;texts&lt;/code&gt; and &lt;code&gt;labels&lt;/code&gt;, as well as encoding the value using the &lt;code&gt;tokenizer&lt;/code&gt; from &lt;code&gt;__init__&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;This encoding is split into two parts: &lt;code&gt;input_ids&lt;/code&gt; and &lt;code&gt;attention_mask&lt;/code&gt;. &lt;code&gt;input_ids&lt;/code&gt; are the tokenized text, and &lt;code&gt;attention_mask&lt;/code&gt; is a binary mask that indicates which tokens are actual words versus padding.&lt;/li&gt;
&lt;li&gt;Everything is transformed into a PyTorch Tensor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the data cleaned up, it was time to create the BERT Classifier. For this project, I used &lt;a href="https://huggingface.co/neuralmind/bert-base-portuguese-cased" rel="noopener noreferrer"&gt;BERTimbau Base&lt;/a&gt;, a pretrained BERT model for Brazilian Portuguese that achieves state-of-the-art performances on three downstream NLP tasks: Named Entity Recognition, Sentence Textual Similarity and Recognizing Textual Entailment.&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%2Fyc285jggabdkkfvtty9b.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%2Fyc285jggabdkkfvtty9b.png" alt="The famous Muppet Bert holding a Timbau, a famous Brazilian music instrument" width="270" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;These people are so creative.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the end, this is what our BERTClassifier looked like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BERTClassifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bert_model_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_classes&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BERTClassifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BertModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bert_model_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dropout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Dropout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Linear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hidden_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_classes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attention_mask&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attention_mask&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;attention_mask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;pooled_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pooler_output&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dropout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pooled_output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;logits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;logits&lt;/span&gt;

&lt;span class="c1"&gt;# Example of initialization
&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;device&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cuda&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;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cuda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_available&lt;/span&gt;&lt;span class="p"&gt;()&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;cpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BERTClassifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;neuralmind/bert-base-portuguese-cased&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# If there's a .pth file to load
&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;load_state_dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bert_classifier.pth&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Breaking this stuff into parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;__init__&lt;/code&gt; function acts as a constructor. It sets the pretrained BertModel from the given &lt;code&gt;bert_model_name&lt;/code&gt;, add a dropout layer to keep things in check and a linear layer to help classify text into &lt;code&gt;num_classes&lt;/code&gt; - in our case, 2 polar opposites.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;forward&lt;/code&gt; function is defined so that it correctly goes through the additional layers we've set up. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please note that I didn't tinker a lot with these, since they were kind of default from the sources that I was studying.&lt;/p&gt;

&lt;p&gt;Given all of that, now we need our &lt;code&gt;train&lt;/code&gt; function. We'll need a lot of things, though:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Set up parameters
&lt;/span&gt;&lt;span class="n"&gt;bert_model_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;neuralmind/bert-base-portuguese-cased&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;num_classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;max_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;
&lt;span class="n"&gt;batch_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;
&lt;span class="n"&gt;num_epochs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;learning_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2e-5&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;train&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data_loader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scheduler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&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;train&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data_loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zero_grad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;input_ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;input_ids&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;attention_mask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;attention_mask&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;labels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;label&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attention_mask&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;attention_mask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CrossEntropyLoss&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;scheduler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;## Begin training
&lt;/span&gt;
&lt;span class="c1"&gt;# Split into train and validation datasets
&lt;/span&gt;&lt;span class="n"&gt;train_texts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val_texts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;train_labels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val_labels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;train_test_split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;texts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;random_state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;val_dataset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TextClassificationDataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val_texts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val_labels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Create DataLoader for batch processing
&lt;/span&gt;&lt;span class="n"&gt;train_dataloader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DataLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;train_dataset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shuffle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;val_dataloader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DataLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val_dataset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Additional steps
&lt;/span&gt;&lt;span class="n"&gt;optimizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AdamW&lt;/span&gt;&lt;span class="p"&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;parameters&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;learning_rate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;total_steps&lt;/span&gt; &lt;span class="o"&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;train_dataloader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;num_epochs&lt;/span&gt;
&lt;span class="n"&gt;scheduler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_linear_schedule_with_warmup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_warmup_steps&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="n"&gt;num_training_steps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;total_steps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A lot to unpack here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, we define some parameters that are going to be used in the model.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;num_classes&lt;/code&gt; is simple: either toxic, or not.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;max_length&lt;/code&gt; as already described is the max length of the encoded text.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;batch_size&lt;/code&gt; would be the number of samples to work through before the model's internal parameters are updated. This value is a choice of balance between reasonable memory requirements without that much loss of performance.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;learning_rate&lt;/code&gt; is &lt;code&gt;2e-5&lt;/code&gt;, which would be &lt;code&gt;0.00002&lt;/code&gt;. If the learning rate is too high, the model might overshoot the minimum of the loss function and fail to converge. If the rate is too low, the model might get stuck in a sub optimal solution. The value of &lt;code&gt;2e-5&lt;/code&gt; is commonly used since it is small enough to allow the model to make gradual progress without overshooting or converging to slowly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's skip the &lt;code&gt;train&lt;/code&gt; method for now and explain the items below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;optimizer&lt;/code&gt; is used to adjust the parameters of our model to normalize the error or loss function. The optimizer changes the weighs and biases of the neurons in response to the error the model produced in its prediction during training. AdamW is a variation of the Adam optimizer.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;total_steps&lt;/code&gt; are the total number of steps that will be run, given that each epoch goes through the entire dataset once - so "amount of epochs" times "amount of rows in each epoch".&lt;/li&gt;
&lt;li&gt;The learning rate scheduler, &lt;code&gt;scheduler&lt;/code&gt;, is used to adjust learning rate during training. It is used to adjust the learning rate during training, and has proven to avoid overfitting, convergence faster and escape saddle points.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Given everything that was said (and I know that it's too much!), now let's break down the &lt;code&gt;train&lt;/code&gt; method:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, it sets the model to training mode.&lt;/li&gt;
&lt;li&gt;Then, enters a loop for each batch of the data loader.&lt;/li&gt;
&lt;li&gt;In this loop, it clears the gradient since they're accumulated in PyTorch. It needs to be reset for each batch.&lt;/li&gt;
&lt;li&gt;It moves the batch to the device being used to training, such as the CPU or GPU.&lt;/li&gt;
&lt;li&gt;Then, it retrieves the input IDs, attention masks and everything else. This is used as input to the model.&lt;/li&gt;
&lt;li&gt;Then, with whatever the model outputs, loss is calcuated with the &lt;code&gt;CrossEntropyLoss&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;It performs backpropagation by calling &lt;code&gt;loss.backward()&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;The &lt;code&gt;optimizer.step()&lt;/code&gt; applies the gradients computed in the previous step to update the model's parameters.&lt;/li&gt;
&lt;li&gt;Finally, the learning rate is adjusted with &lt;code&gt;scheduler.step()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Phew! A lot of things to uncover.&lt;/p&gt;

&lt;p&gt;In the end, we can just call the &lt;code&gt;train&lt;/code&gt; function for each epoch, and then save the model as a &lt;code&gt;.pth&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;epoch&lt;/span&gt; &lt;span class="ow"&gt;in&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;num_epochs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Epoch &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;epoch&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;num_epochs&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;train&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;train_dataloader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scheduler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;accuracy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val_dataloader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Validation Accuracy: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;accuracy&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&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;state_dict&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bert_classifier.pth&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This model will be available in the path, and can be imported and used to predict the toxicity of texts! Here's one example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;predict_sentiment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&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;eval&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;encoding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;return_tensors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pt&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;max_length&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;truncation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;input_ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;input_ids&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;attention_mask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;attention_mask&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;no_grad&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attention_mask&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;attention_mask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;preds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&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="n"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&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="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;preds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="c1"&gt;# Load the model from the .pth file
&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BERTClassifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;neuralmind/bert-base-portuguese-cased&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&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;load_state_dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bert_pt_classifier.pth&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;predict_sentiment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello world!&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# Returns 0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;And that's it! If you want to check it out and train/test this model yourself, feel free to check the code in &lt;a href="https://github.com/AlvBarros/toldbr-bert-text-classification-pt-br" rel="noopener noreferrer"&gt;my GitHub repository&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;This post was born out of &lt;a href="https://www.kaggle.com/competitions/ml-olympiad-toxic-language-ptbr-detection" rel="noopener noreferrer"&gt;my first Kaggle competition&lt;/a&gt;! &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%2F5hfkj9fb2jx9fe41da9x.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%2F5hfkj9fb2jx9fe41da9x.png" alt="Image of the final leaderboard for the competition, with the rest of the candidates censored." width="800" height="351"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Despite not winning the competition, I'm still very close to the top, with &lt;strong&gt;0.00952&lt;/strong&gt; setting me apart from the first place, so I hope my experience can also teach other beginners something useful!&lt;/p&gt;

&lt;p&gt;I'm already a software engineer at work, but artificial intelligence has always been a source of curiosity for me. When I was in college, I had a brief exposure to computer vision and even ended up publishing some scientific articles. Now, I'm trying to make up for lost time studying and learning AI again. Follow me to join me on my journey!&lt;/p&gt;

&lt;h2&gt;
  
  
  Special thanks
&lt;/h2&gt;

&lt;p&gt;First of all, special thanks to &lt;a href="https://www.kaggle.com/pedrogengo" rel="noopener noreferrer"&gt;Pedro Gengo&lt;/a&gt; and the folks over at Tensorflow User Group São Paulo for creating the Kaggle Competition and inspiring this project!&lt;/p&gt;

&lt;p&gt;Also, huge thanks to &lt;a href="https://medium.com/@khang.pham.exxact/text-classification-with-bert-7afaacc5e49b" rel="noopener noreferrer"&gt;Kang Pham&lt;/a&gt; for writing this tutorial where I got most of this code!&lt;/p&gt;

&lt;p&gt;And finally, thanks for Pedro Henrique Vieira de Lima whose work on &lt;a href="https://bdm.unb.br/bitstream/10483/36836/1/2023_PedroHenriqueVieirDeLima_tcc.pdf" rel="noopener noreferrer"&gt;Detecção de Comentários Tóxicos em Chats e Redes Sociais com Deep Learning&lt;/a&gt; was crucial for hitting a higher score on the leaderboard.&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>nlp</category>
      <category>tensorflow</category>
    </item>
    <item>
      <title>Automate Flutter app delivery to AppCenter with GitHub Actions</title>
      <dc:creator>AlvBarros</dc:creator>
      <pubDate>Fri, 06 Oct 2023 22:31:42 +0000</pubDate>
      <link>https://dev.to/alvbarros/automate-flutter-app-delivery-to-appcenter-with-github-actions-3fec</link>
      <guid>https://dev.to/alvbarros/automate-flutter-app-delivery-to-appcenter-with-github-actions-3fec</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this post, you'll see how to automate the delivery of your Flutter app to the testing team. For this to work, your app must have follow these conditions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're developing a &lt;a href="https://flutter.dev" rel="noopener noreferrer"&gt;Flutter&lt;/a&gt; app;&lt;/li&gt;
&lt;li&gt;Your code is hosted on &lt;a href="https://github.com" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;Your testing team is using &lt;a href="https://appcenter.ms" rel="noopener noreferrer"&gt;AppCenter&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Got it? Let's begin.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Continuous Integration?
&lt;/h2&gt;

&lt;p&gt;According to &lt;a href="https://www.atlassian.com/continuous-delivery/continuous-integration" rel="noopener noreferrer"&gt;Atlassian's Max Rehkopf&lt;/a&gt;, it's about &lt;strong&gt;automatically running builds and tests with every change&lt;/strong&gt;. This speeds up development, since it is happening automatically, the developer can focus on the development of new features and leave validation and testing to automated tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ok, so what's Continuous Delivery then?
&lt;/h2&gt;

&lt;p&gt;Taking inspiration from &lt;a href="https://www.atlassian.com/continuous-delivery/principles/continuous-integration-vs-delivery-vs-deployment" rel="noopener noreferrer"&gt;Pittet's post&lt;/a&gt;, CD is &lt;strong&gt;automatic deployment of the code on testing and/or production environment&lt;/strong&gt;. It's often confused with Continuous &lt;em&gt;Deployment&lt;/em&gt;, which is the automated release to the end customers.&lt;/p&gt;

&lt;p&gt;In this post we'll focus on &lt;strong&gt;Continuous Delivery&lt;/strong&gt;, since we'll be automating the deployment of your app to AppCenter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 - Setting up a Runner for GitHub Actions
&lt;/h2&gt;

&lt;p&gt;If your code is hosted on GitHub, the best approach to DevOps is to write GitHub Actions. You can read more about Actions &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;here&lt;/a&gt;, but everything that you need to know will be explained later on. For now, you have to setup a &lt;strong&gt;Runner&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://github.com/actions/runner" rel="noopener noreferrer"&gt;runner&lt;/a&gt; is where your action's jobs will be run. It can be a hosted virtual environment, or you can self-host a runner in your machine.&lt;/p&gt;

&lt;p&gt;To register your own machine as a runner, you must go to the Settings of your repository and follow the instructions on &lt;strong&gt;Settings &amp;gt; Actions &amp;gt; Runner&lt;/strong&gt;.&lt;br&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%2Faonrgg2wxfqdwfhoviix.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%2Faonrgg2wxfqdwfhoviix.png" alt="To set up a runner, go to Settings &amp;gt; Actions &amp;gt; Runner" width="800" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There you'll see a green button &lt;strong&gt;"New self-hosted runner"&lt;/strong&gt;. Click on it and then follow the steps. It is simply running a few commands on you terminal, so I'll not be covering it here.&lt;/p&gt;

&lt;p&gt;In the end, you should be running your runner and it will be shown in the same page of the Settings, such as below.&lt;br&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%2Fl2cdh6ydx86l7o4hacs1.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%2Fl2cdh6ydx86l7o4hacs1.png" alt="Runners page displaying my machine as an Idle Runner" width="800" height="573"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you have any issues on this part, feel free to leave a comment below.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Step 2 - Set up your AppCenter app
&lt;/h2&gt;

&lt;p&gt;On your AppCenter app's settings, go to &lt;strong&gt;Settings &amp;gt; App API Tokens&lt;/strong&gt;. There, you can create a token that'll be used on our Actions workflow. &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%2Ftywy93uo5j1q9jwzv9sh.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%2Ftywy93uo5j1q9jwzv9sh.png" alt="AppCenter app's Settings showing the Add API Tokens page" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;"New API Token"&lt;/strong&gt;. You'll be asked to set up a name and access for your token. Set whatever you'd like, but the token must have &lt;strong&gt;Full access&lt;/strong&gt;. Don't worry, only you can see this token.&lt;/p&gt;

&lt;p&gt;When the pop-up with the token appears - such as the one below, copy the token and save it somewhere safe. You &lt;strong&gt;cannot&lt;/strong&gt; see it again, and if you happen to lose it, you must delete it and create a new one.&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%2Fu1lg0bfwqfnpcs8q57im.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%2Fu1lg0bfwqfnpcs8q57im.png" alt="AppCenter's pop-up with the API token censored" width="510" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With your AppCenter API Token, go back to your repository on GitHub. On &lt;strong&gt;Settings &amp;gt; Secrets and variables &amp;gt; Actions&lt;/strong&gt;, we'll create a Secret for our repository.&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%2Fiv77nax84r8wqx2nd10t.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%2Fiv77nax84r8wqx2nd10t.png" alt="Settings &amp;gt; Secrets and variables &amp;gt; Actions" width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;secret&lt;/strong&gt; is a variable that is used by our GitHub actions but is not displayed for who does not have permission. The automated workflow can use the value, but no one is able to see what it is. This enables the user to have environment variables such as AppCenter's API Token without it being compromised or leaked. For more information on secrets, refer to the &lt;a href="https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, click on &lt;strong&gt;"New repository secret"&lt;/strong&gt; and create a &lt;strong&gt;APPCENTER_API_TOKEN&lt;/strong&gt; and paste the value of the token previously created. If you've done everything correctly, this must be what you see on your page.&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%2Fm7v0cgluygl0jy6wah80.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%2Fm7v0cgluygl0jy6wah80.png" alt="Secrets and variables page with the new created APPCENTER_API_TOKEN" width="794" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can finally start creating workflows for our repository.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3 - Creating your GitHub Actions Workflow
&lt;/h2&gt;

&lt;p&gt;First of all, you repository needs a &lt;strong&gt;.github&lt;/strong&gt; folder on the root folder. Then, you create a &lt;strong&gt;workflows&lt;/strong&gt; folder. There, we'll create a &lt;strong&gt;main.yml&lt;/strong&gt; file. The end result should be something like this:&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%2Fkvsxvr1gmdmthxa331o9.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%2Fkvsxvr1gmdmthxa331o9.png" alt="Printscreen of the .github/workflows folder" width="800" height="846"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that the file doesn't have to be named &lt;code&gt;main.yml&lt;/code&gt;, this is just for this example.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the &lt;strong&gt;main.yml&lt;/strong&gt; file, we must add some code so that it does what we want. Start by writing this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Deploy App on AppCenter
on:
  push:
    branches:
      - main
      - 'releases/**'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt;: Self explanatory. Sets the name of this workflow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;on&lt;/strong&gt;: Defines the triggers of this workflow. On our case, we want this workflow to be triggered on every &lt;code&gt;push&lt;/code&gt; that happens on the &lt;code&gt;main&lt;/code&gt; branch, or any other branch that starts with &lt;code&gt;releases/&lt;/code&gt;, such as &lt;code&gt;releases/1.0.0&lt;/code&gt;, &lt;code&gt;releases/hotfix-login&lt;/code&gt;, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;For more information on &lt;code&gt;on&lt;/code&gt; tag, see the &lt;a href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#onpushpull_requestpull_request_targetpathspaths-ignore" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But still, it's not doing anything. So now we need to add &lt;a href="https://docs.github.com/en/actions/using-jobs/using-jobs-in-a-workflow" rel="noopener noreferrer"&gt;Jobs&lt;/a&gt;. Jobs are what make up workflows, and are the steps you want to execute.&lt;/p&gt;

&lt;p&gt;For this post, we'll set up these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up Flutter;&lt;/li&gt;
&lt;li&gt;Set up AppCenter CLI;&lt;/li&gt;
&lt;li&gt;Build the app's package;&lt;/li&gt;
&lt;li&gt;Deploy the package to AppCenter.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;In this post, only Android will be covered. Follow me to know when the post for iOS is released!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 3.1 - Set up Flutter
&lt;/h2&gt;

&lt;p&gt;Now that you have your &lt;code&gt;main.yml&lt;/code&gt; file configured, we can add &lt;code&gt;jobs&lt;/code&gt; to achieve what we want. Start by adding a &lt;code&gt;jobs&lt;/code&gt; and a "Set up Flutter" step, such as the code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jobs:
  setup-flutter:
    name: Setup Flutter
    runs-on: self-hosted
    steps:
      - name: Check out repository code
        uses: actions/checkout@v3
      - name: Install jq
        uses: dcarbone/install-jq-action@v2.0.2
      - uses: subosito/flutter-action@v2
        with:
          channel: master
          architecture: x64
      - run: flutter pub get
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's take this apart:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;jobs&lt;/strong&gt;: Defines jobs that must be run for this workflow. These can be run in parallel or sequentially. By default, they are run in parallel. More information later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;runs-on&lt;/strong&gt;: Defines on what kind of Runner this job can be run. Since we've defined our self-hosted runner in the previous steps, we just add this value.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;steps&lt;/strong&gt;: Defines the steps for this job. Each will be run sequentially.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you pay attention, we already created 3 steps. They have two tags: &lt;strong&gt;name&lt;/strong&gt; and &lt;strong&gt;uses&lt;/strong&gt;. Name is self explanatory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Uses&lt;/strong&gt; defines what action is used on this step. In the first case, &lt;strong&gt;actions/checkout@v4&lt;/strong&gt; is used. This format says what repository and action is used. Below is the list of actions used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;actions/checkout@&lt;/strong&gt;: Checks out the code in the runner. This makes sure that the workflow is being run on updated code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;dcarbone/install-jq-action&lt;/strong&gt;: This actions installs &lt;code&gt;jq&lt;/code&gt; on the runner machine. It's a lightweight command-line JSON processor. For more information, check it's &lt;a href="https://jqlang.github.io/jq/" rel="noopener noreferrer"&gt;page&lt;/a&gt;. This is not necessary to build Flutter, but it's used in other actions later on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;subosito/flutter-action&lt;/strong&gt;: This action installs and runs Flutter commands. It's what we'll use to get dependencies and build our package. It can also be used to run our tests and check for coverage, but it's not being implemented in this guide. This action has a &lt;code&gt;run&lt;/code&gt; parameter, which defines the specific command we want to be run.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you pay attention, all these actions are actually public repositories that we can use. GitHub Actions have a &lt;a href="https://github.com/marketplace?type=actions" rel="noopener noreferrer"&gt;public marketplace&lt;/a&gt; that you can add actions that have been developed by the community. To check what's the code is doing, you can go to the repository and check it. It's best to see what it's doing to make sure that you're not using anything with a specific vulnerability.&lt;/p&gt;

&lt;p&gt;So to summarize, we've set up a workflow that on every push that happens on &lt;strong&gt;master&lt;/strong&gt; or &lt;strong&gt;release/**&lt;/strong&gt; installs Flutter and the Pub dependencies on the runner.&lt;/p&gt;

&lt;p&gt;Now, we can add the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3.2 - Set up AppCenter CLI
&lt;/h2&gt;

&lt;p&gt;This step is going to be easier since we already know what we're doing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  setup-appcenter-cli: # must have node and npm installed!
      name: Setup AppCenter CLI
      runs-on: self-hosted
      steps:
      - name: Install appcenter-cli
        uses: charliealbright/appcenter-cli-action@v1.0.1
        with:
          token: '${{secrets.APPCENTER_API_TOKEN}}'
          command: 'appcenter help'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now have a new tag to go over:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;with&lt;/strong&gt;: This sets some parameters to be given to the action as an input. 
In this case, we add &lt;code&gt;token&lt;/code&gt; and &lt;code&gt;command&lt;/code&gt;. If you pay attention, we're using &lt;code&gt;secrets.APPCENTER_API_TOKEN&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Secret&lt;/strong&gt; is an object that contains every variable we've set in the repository's secret. Since we've set APPCENTER_API_TOKEN, this token can now be used in this action. Again, &lt;strong&gt;make sure that you know what your actions are doing&lt;/strong&gt;.&lt;br&gt;
We then add &lt;code&gt;"${{"&lt;/code&gt; and &lt;code&gt;"}}"&lt;/code&gt; around the variable so that Actions knows that it must change this value to the one set on the secrets.&lt;/p&gt;

&lt;p&gt;So now we have two steps: setting up Flutter and AppCenter CLI.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3.3 - Call Deploy Android job on the main workflow
&lt;/h2&gt;

&lt;p&gt;We now can use some of the superpowers of GitHub Actions - creating different jobs on different files. Add this specific job below &lt;code&gt;setup-appcenter-cli&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  deploy_android:
    name: Deploy Android
    needs: [setup-flutter, setup-appcenter-cli]
    uses: ./.github/workflows/deploy_android.yml
    with:
      file: './build/app/outputs/apk/release/app-release.apk'
      name: 'AlvaroBarrosC/GithubAction-Android'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now have two tags to go over:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;needs&lt;/strong&gt;: This sets some requirements for this job. In our case, it needs Flutter and AppCenter CLI to be set up. This also means that this Deploy job will be run sequentially.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;uses&lt;/strong&gt;: We've already seen this tag, but now we're giving a local path. This will use a &lt;code&gt;deploy_android.yml&lt;/code&gt; file that we've created on &lt;code&gt;workflows&lt;/code&gt; folder. So let's create the file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As described previously, the &lt;strong&gt;with&lt;/strong&gt; tag adds some inputs. In this case, we've added &lt;strong&gt;file&lt;/strong&gt; and &lt;strong&gt;name&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;file&lt;/strong&gt;: This must be the path to the file that is generated by the Flutter &lt;code&gt;build&lt;/code&gt; command. Above is the default output directory, but this can be changed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt;: This one is the username, slash and the app’s name on AppCenter. Mine is &lt;code&gt;AlvaroBarrosC&lt;/code&gt; and &lt;code&gt;GithubAction-Android&lt;/code&gt;, but you must change it to your own.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 4 - Create Deploy Android workflow
&lt;/h2&gt;

&lt;p&gt;As said in the previous step, create the file on &lt;code&gt;.github/workflow/deploy_android.yml&lt;/code&gt;, the same folder where your &lt;code&gt;main.yml&lt;/code&gt; file is located. Then, you can paste this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Deploy Android App on AppCenter
on: 
  workflow_call:
    inputs:
      file:
        description: 'The path to the file to be released'
        required: true
        type: string
      name:
        description: 'The name of the app'
        required: true
        type: string
      group:
        description: 'The group that will have access to the version released'
        required: false
        type: string
        default: '"Collaborators"'
jobs:
  build:
    name: Build .apk file
    runs-on: self-hosted
    steps:
      - run: flutter build apk --release --verbose
  Deploy:
    name: Deploy file to AppCenter
    needs: [build]
    runs-on: self-hosted
    steps:
      - name: AppCenter CLI Action
        uses: charliealbright/appcenter-cli-action@v1.0.1
        with:
          token: ${{secrets.APPCENTER_API_TOKEN}}
          command: 'appcenter distribute release -f ${{inputs.file}} --app ${{inputs.name}} --group ${{inputs.group}}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You now can see how the inputs are defined on the top of the file. They have some metadata, such as &lt;code&gt;required&lt;/code&gt;, &lt;code&gt;type&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt;. You can also see them being used on the &lt;code&gt;command&lt;/code&gt; parameter of the AppCenter CLI Action. By using &lt;code&gt;${{inputs.[field]}}&lt;/code&gt;`, you place the value given when the workflow was called.&lt;/p&gt;

&lt;p&gt;We can now make a push on any change in the affected branches and see the workflow being run. Make sure your runner is running.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5 - Deploy!
&lt;/h2&gt;

&lt;p&gt;If you followed every step correctly, whenever you go to your Repository’s &lt;strong&gt;Actions&lt;/strong&gt; tab, you can see your previous runs there. Also, you can debug and see the log of the steps.&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%2Fqrfofle0oxvvobmbfzt8.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%2Fqrfofle0oxvvobmbfzt8.png" alt="Printscreen showing available workflows" width="800" height="216"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that iOS deployment was not covered on this post.&lt;/p&gt;
&lt;/blockquote&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%2Ftqu6u75r9qx4g79whz3z.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%2Ftqu6u75r9qx4g79whz3z.png" alt="The execution of the workflow, step by step" width="800" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks for reading!
&lt;/h2&gt;

&lt;p&gt;If you've missed any of the steps or is encountering any problem, you can check the code on &lt;a href="https://github.com/AlvBarros/flutter-appcenter-github-action" rel="noopener noreferrer"&gt;this repo&lt;/a&gt;. Feel free to comment on this post with any questions that you have.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>devops</category>
      <category>githubactions</category>
      <category>android</category>
    </item>
    <item>
      <title>Dependency Injection in Flutter</title>
      <dc:creator>AlvBarros</dc:creator>
      <pubDate>Wed, 16 Aug 2023 17:14:00 +0000</pubDate>
      <link>https://dev.to/alvbarros/dependency-injection-in-flutter-598k</link>
      <guid>https://dev.to/alvbarros/dependency-injection-in-flutter-598k</guid>
      <description>&lt;p&gt;In this article I'll attempt to teach you what it is, how to do it and why would you do it, as well as providing examples and a link to a &lt;a href="https://github.com/AlvBarros/dependency_injection" rel="noopener noreferrer"&gt;repo on GitHub&lt;/a&gt; where you can check the code and try it for yourself. Now, moving on.&lt;/p&gt;

&lt;p&gt;According to &lt;a href="https://en.wikipedia.org/wiki/Dependency_injection" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In software engineering, dependency injection is a design pattern in which an object or function receives other objects or functions that it depends on. A form of inversion of control, dependency injection aims to separate the concerns of constructing objects and using them, leading to loosely coupled programs. The pattern ensures that an object or function which wants to use a given service should not have to know how to construct those services. Instead, the receiving 'client' (object or function) is provided with its dependencies by external code (an 'injector'), which it is not aware of.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;So, in other words:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instead of creating objects inside a class or method, those objects are "injected" from outside;&lt;/li&gt;
&lt;li&gt;The class does not need to know how to create the objects it depends on, it just needs to know how to use them;&lt;/li&gt;
&lt;li&gt;This generates code that is easier to test and is more maintainable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Like anything in life, DI comes with some Pros and Cons.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Makes your code &lt;strong&gt;easier to test&lt;/strong&gt;, since you can just inject mocks in your classes;&lt;/li&gt;
&lt;li&gt;Makes your code &lt;strong&gt;easier to maintain&lt;/strong&gt;, as changes to the implementation of the injected objects can be made without affecting the class or method that depends on them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DI can &lt;strong&gt;add more complexity&lt;/strong&gt; to your project, especially if done improperly;&lt;/li&gt;
&lt;li&gt;Injecting dependencies can introduce &lt;strong&gt;performance overhead&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;DI can introduce &lt;strong&gt;runtime errors&lt;/strong&gt;, such as null pointer exceptions, if dependencies are not properly managed or injected.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Car example
&lt;/h3&gt;

&lt;p&gt;So, let's start with some code. Suppose you have a Car class, that has an Engine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Car&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Engine&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Car&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Null reference exception&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;For this &lt;code&gt;Car&lt;/code&gt; to work, you need a working &lt;code&gt;Engine&lt;/code&gt;. That, however, is another class that has a bunch of complexities and other requirements that do not concern the car itself.&lt;/p&gt;

&lt;p&gt;Following the principles of dependency injection, this is what we can do:&lt;/p&gt;

&lt;h4&gt;
  
  
  Constructor injection
&lt;/h4&gt;

&lt;p&gt;The dependencies are passed to a class through its constructor.&lt;/p&gt;

&lt;p&gt;This pattern makes it clear what dependencies a class require to function, and it ensures that the dependencies are available as soon as the class is created.&lt;/p&gt;

&lt;p&gt;If we implement constructor injection in our &lt;code&gt;Car&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Car&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Engine&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Car&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// engine is not null!&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;Since &lt;code&gt;Car.engine&lt;/code&gt; is &lt;code&gt;final&lt;/code&gt; and also required in the construcotr, we make sure that it will never be null.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;car&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Car&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;car&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&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;h3&gt;
  
  
  Adding more parts
&lt;/h3&gt;

&lt;p&gt;Now, let's imagine that you're a car manufacturer and you are creating parts of a car. Since cars are not only made of engines, you now have this class structure:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please note that I'm not a car manufacturer and this is not all the parts a car needs.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Car&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Engine&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Wheel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;wheels&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Door&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;doors&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Window&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;windows&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Car&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;wheels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;windows&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;rollDownAllWindows&lt;/span&gt;&lt;span class="p"&gt;()&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;var&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;windows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;rollDown&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;openAllDors&lt;/span&gt;&lt;span class="p"&gt;()&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;var&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;doors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since the engine is &lt;code&gt;final&lt;/code&gt; and must be passed on in the constructor, the class won't compile until you give it a working engine. It doesn't make sense that your doors doesn't work until you have a working engine.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;With the construction injection approach, you're only able to have a &lt;code&gt;Car&lt;/code&gt; instance after you have all the pieces already done, and can not have an "incomplete" &lt;code&gt;Car&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Setter injection
&lt;/h4&gt;

&lt;p&gt;The dependencies are set on a class through setter methods.&lt;/p&gt;

&lt;p&gt;This pattern allows for more flexibility as the dependencies can be set or changed after the class is created.&lt;/p&gt;

&lt;p&gt;Whenever you have an instance of &lt;code&gt;Car&lt;/code&gt;, you can just use &lt;code&gt;setEngine&lt;/code&gt; to set an engine to the car. This fixes the previous problem and we can now have a &lt;code&gt;Car&lt;/code&gt; and later give it an engine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Car&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Engine&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Wheel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;wheels&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Door&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;doors&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Window&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;windows&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Car&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;wheels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;windows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;setEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Engine&lt;/span&gt; &lt;span class="n"&gt;newEngine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now all you have to do is call &lt;code&gt;setEngine&lt;/code&gt; whenever your engine is ready to be placed in the car. You also must add some validation so that you don't have runtime errors happening in your code. For more information on how to properly prevent these issues, take a look at &lt;a href="https://dart.dev/null-safety" rel="noopener noreferrer"&gt;Null safety in Dart&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other types of dependency injection
&lt;/h3&gt;

&lt;p&gt;These other types will not be covered in this example, so these are just introductions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Interface injection
&lt;/h4&gt;

&lt;p&gt;The class implements an interface which defines the methods for injecting the dependencies.&lt;/p&gt;

&lt;p&gt;This pattern allows for more abstraction and decoupling of the code, as the class does not have to depend on a specific implementation of the interface.&lt;/p&gt;

&lt;h4&gt;
  
  
  Ambient context
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;You may be familiar with the &lt;a href="https://pub.dev/packages/provider" rel="noopener noreferrer"&gt;provider pub package&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A shared context is used to provide the dependencies to the classes that require them.&lt;/p&gt;

&lt;p&gt;This pattern can be useful in situations where multiple classes need access to the same dependencies.&lt;/p&gt;

&lt;h4&gt;
  
  
  Service locator
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;You may be familiar with the &lt;a href="https://pub.dev/packages/get_it" rel="noopener noreferrer"&gt;get_it pub package&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A central registry is used to manage and provide the dependencies to the classes that require them.&lt;/p&gt;

&lt;p&gt;This pattern can make it easier to manage dependencies in large applications, but it can also make the code more complex and harded to test.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ok, but why tho?
&lt;/h3&gt;

&lt;p&gt;In one of my projects I needed to create an authentication layer so that my users can create accounts and authenticate themselves.&lt;/p&gt;

&lt;p&gt;Since I was still deciding on which one to use - since it needed to be free and easy to scale - I created a dependency injection structure so that I can easily swap out whenever I'd like to test another authentication service.&lt;/p&gt;

&lt;p&gt;This is the structure that I've got:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthenticationRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;AuthenticationProvider&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;AuthenticationRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UserSession&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&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="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&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="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="s"&gt;'Failed to authenticate'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This class has a method &lt;code&gt;signIn&lt;/code&gt; that takes an user's &lt;code&gt;email&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt;, then give it to the corresponding provider. It also returns an &lt;code&gt;UserSession&lt;/code&gt;, class responsible to store the current user's data and authentication token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserSession&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;UserSession&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;sessionToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;""&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;Take notice of &lt;code&gt;AuthenticationRepository.provider&lt;/code&gt;. It's an instance of the class &lt;code&gt;AuthenticationProvider&lt;/code&gt;. Here's the configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthenticationProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UserSession&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&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;Since this class is abstract, in order to create a repository that actually works, you need to give it an implementation.&lt;/p&gt;

&lt;p&gt;So I have created two classes: &lt;code&gt;FirebaseProvider&lt;/code&gt; and &lt;code&gt;CognitoProvider&lt;/code&gt;. These classes are responsible for managin user authentication with Firebase's and Cognito's APIs respectively.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There's a pub package &lt;a href="https://pub.dev/packages/firebase_core" rel="noopener noreferrer"&gt;for Firebase integration&lt;/a&gt; and also one &lt;a href="https://pub.dev/packages/amazon_cognito_identity_dart_2" rel="noopener noreferrer"&gt;for Cognito integration&lt;/a&gt;.&lt;br&gt;
These packages, however, do not seamlessly fit into the &lt;code&gt;AuthenticationProvider&lt;/code&gt; abstract class showed in this example.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So now, in order to authenticate, we just need to decide which one we want to use. Imagine you have your &lt;code&gt;AuthenticationRepository&lt;/code&gt; stored in a service locator such as &lt;em&gt;GetIt&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// setting up &lt;/span&gt;
&lt;span class="n"&gt;GetIt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registerSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AuthenticationRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;AuthenticationRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CognitoProvider&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// authenticating an user&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GetIt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AuthenticationRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing example
&lt;/h3&gt;

&lt;p&gt;To showcase how you can use DI to make better tests and mock classes easily, here's an example of &lt;code&gt;MockAuthenticationProvider&lt;/code&gt; that enables testing on &lt;code&gt;AuthenticationRepository&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can begin by creating the mocked provider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MockAuthenticationProvider&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="n"&gt;AuthenticationProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;successPassword&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"123"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;UserSession&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;userSession&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;MockAuthenticationProvider&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userSession&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UserSession&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;successPassword&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="n"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userSession&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&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;Note that the class above has a static &lt;code&gt;successPassword&lt;/code&gt; property. This is so that we can implement success and failure methods, but it is in no way necessary. Feel free to implement any logic that you'd like.&lt;/p&gt;

&lt;p&gt;And now you can then create the mock factory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;AuthenticationRepository&lt;/span&gt; &lt;span class="nf"&gt;mockRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;mockUserSession&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UserSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;username:&lt;/span&gt; &lt;span class="s"&gt;"mock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;email:&lt;/span&gt; &lt;span class="s"&gt;"mock@mail.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;sessionToken:&lt;/span&gt; &lt;span class="s"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;mockProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MockAuthenticationProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;userSession:&lt;/span&gt; &lt;span class="n"&gt;mockUserSession&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;AuthenticationRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockProvider&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;By using this &lt;code&gt;AuthenticationRepository&lt;/code&gt;, we can easily test its methods without needing to integrate with either Cognito nor Firebase. Here's an example of a successful unit test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Should return a valid UserSession'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mockRepository&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MockAuthenticationProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;successPassword&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sessionToken&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&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;Note that we're trying to signin with an &lt;code&gt;"email"&lt;/code&gt; and &lt;code&gt;MockAuthenticationProvider.successPassword&lt;/code&gt;, which is a way to force the provider to return an &lt;code&gt;UserSession&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, testing for failures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Should throw if UserSession comes null from provider'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mockRepository&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"incorrect password"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;userSession&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Should throw an exception"&lt;/span&gt;&lt;span class="p"&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="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"Failed to authenticate"&lt;/span&gt;&lt;span class="p"&gt;);&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;h3&gt;
  
  
  Ending
&lt;/h3&gt;

&lt;p&gt;And that's it!&lt;/p&gt;

&lt;p&gt;Thanks for reading through the end with this article. This is my first here on dev.to, so feel free to leave any feedbacks.&lt;/p&gt;

&lt;p&gt;Here's the &lt;a href="https://github.com/AlvBarros/dependency_injection" rel="noopener noreferrer"&gt;source code&lt;/a&gt; once again. Feel free to open an issue or comment down below.&lt;/p&gt;

&lt;p&gt;See ya!&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>architecture</category>
      <category>development</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
