<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Vidhur Kumar on Medium]]></title>
        <description><![CDATA[Stories by Vidhur Kumar on Medium]]></description>
        <link>https://medium.com/@vidhur2k?source=rss-296557a3927f------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*CiDd7HlVvO-IyiWmUxwAOw.png</url>
            <title>Stories by Vidhur Kumar on Medium</title>
            <link>https://medium.com/@vidhur2k?source=rss-296557a3927f------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 05:41:53 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@vidhur2k/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[A Helpful Checklist While Adding Functionality to a React-Redux app]]></title>
            <link>https://medium.com/swlh/a-helpful-checklist-while-adding-functionality-to-a-react-redux-app-76088a9da634?source=rss-296557a3927f------2</link>
            <guid isPermaLink="false">https://medium.com/p/76088a9da634</guid>
            <category><![CDATA[reactjs]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[redux]]></category>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[web-development]]></category>
            <dc:creator><![CDATA[Vidhur Kumar]]></dc:creator>
            <pubDate>Sat, 06 Jun 2020 02:32:18 GMT</pubDate>
            <atom:updated>2020-07-07T06:23:02.580Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/680/1*9MKCZn6W-GZ8KZ1tTjRtaQ.jpeg" /></figure><h3><strong>Background</strong></h3><p>Over the last few years, React has catapulted to the top of the list for building reactive user interfaces. The framework incorporates a component-based system, with each component being able to:</p><ul><li>Take input data (accessed via this.props ), and</li><li>Maintaining internal state data (accessed via this.state )</li></ul><p>These two concepts allow us to build applications that are able to pass and mutate data with ease. However, with a growing codebase comes a need to maintain a hierarchy of components that are easily testable, debuggable, and reusable. The props of each component remains immutable and cannot cause any behavioral inconsistencies. It is the components’ state that, while passed around and mutated, may cause unpredictable changes to the application and hurt its scalability and maintainability. Enter <strong>Redux</strong>, a third-party library that acts as a state container by maintaining a centralized state tree and allows mutations by means of emitting actions. Integrating Redux into a React application involves an expensive initial overhead cost, but pays the developer handsomely when the application evolves into one with multiple components that have a reasonable amount of data mutation, where having a single source of truth for the state comes in real handy!</p><blockquote>Integrating Redux into a React application involves an expensive initial overhead cost, but pays the developer handsomely when the application evolves into one with multiple components that have a reasonable amount of data mutation, where having a single source of truth for the state comes in real handy!</blockquote><p>This article puts together what I find to be a useful mental checklist to use while adding any new <em>state-related </em>functionality to a React application. If you don’t have a basic understanding of Redux, <a href="https://react-redux.js.org/introduction/basic-tutorial">this</a> tutorial provides a great introduction!</p><h3>Assumptions</h3><p>This tutorial assumes the following:</p><ul><li>An understanding of the React framework, including JSX.</li><li>An understanding of the Redux library, including the entire Redux workflow from providing the application with the <strong>store </strong>to emitting <strong>actions </strong>and performing the appropriate state mutation using the concept of <strong>reducers.</strong></li></ul><p>The mental checklist involves us walking through an example. We will be working under the assumption that we have an application that has been connected to the store and has a boilerplate for writing actions and reducers. This helps us better appreciate the efficacy of the checklist as we will be adding to an existing codebase and, should we miss a step in the process, open ourselves up to spending a lot of time debugging.</p><h3>A Short Note on the Example</h3><p>The example we will be working with is (drumroll…) the todo list! Yes, it’s a cliche and while it does not involve any glorious functionality, it is an extremely effective and intelligible way of explaining concepts :)</p><p>We assume we have the following implementations:</p><ul><li>A TodoList component that renders a list of todos.</li><li>A Todo component that renders a single todo item.</li><li>An AddTodo button that, when clicked, emits an action to add the specified todo item to the list.</li></ul><p>We will be implementing the following <em>state-related </em>functionality:</p><ul><li>A DeleteTodo button that will be placed inside the Todo component and. when clicked, emits an action to delete the corresponding todo item from the list.</li></ul><h3>The Checklist</h3><p>The checklist operates in a linear fashion, where each step(s) deal with a specific segment of the Redux workflow. In this case, we go with the following linear sequence:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/821/1*gQJQQ9J59J0nNm-ftvGKjQ.png" /><figcaption>Each step(s) correspond to a different segment of the workflow. The segments we have here are: action declaration and emission, reducer declaration and connection to the store, and connecting the state to the appropriate component</figcaption></figure><h4>1. Add the action to actionTypes.js</h4><pre><strong>// actionTypes.js<br>export const</strong> ADD_TODO = &quot;ADD_TODO&quot;;<br><em>// What we need to add: the delete todo action<br></em><strong>export const</strong> DELETE_TODO = &quot;DELETE_TODO&quot;;</pre><p>In the action segment of the workflow, we should be thinking along the lines of “I need to define an action that can be dispatched on demand”. The actionTypes file maintains the set of constants corresponding to different actions. It is unnecessary for smaller projects, but if you expect your project to grow then it is a good idea to have a single source of truth by means of the constants.</p><h4>2. Define the action creator</h4><pre><strong>// todoActions.js<br>import</strong> * as TYPES from &quot;./actionTypes&quot;;<br><strong>let</strong> nextTodoId = 0;<br>...<br>// What we need to create: the delete todo action.<br><strong>export const</strong> deleteTodo = content =&gt; ({<br>    type: TYPES.DELETE_TODO,<br>    payload: {<br>    id: --nextTodoId,<br>    content<br>    }<br>})</pre><p>Once we have the DELETE_TODOaction constant, simply import it into the appropriate creator file and define the action.</p><h4>3. Handle the action emission in the reducer</h4><pre><strong>// todoReducer.js<br>import</strong> * as TYPES from &quot;../actionTypes&quot;;<br><strong>const</strong> initialState = {<br>    allIds: [],<br>};<br><strong>export default function</strong>(state = initialState, action) {<br><strong>switch</strong>(action.type) {</pre><pre>...<br>    <strong>case</strong> TYPES.DELETE_TODO: {<br>        <strong>let</strong> newIds = allIds;<br>        newIds.splice(newIds.indexOf(action.payload.id), 1)<br>        <strong>return</strong> {<br>           ...state,<br>           newIds: newIds<br>        }<br>     }<br>}</pre><p>Now that we have an action to dispatch, we need to be thinking along the lines of “what happens to the state when the action is dispatched”? This helps us maintain the linear thought process above. From the action segment, we move into the reducer creation step. We import the DELETE_TODO action into the appropriate reducer file and define the state mutation that takes place when the DELETE_TODO action is emitted.</p><h4>4. Add the reducer to the store</h4><pre><strong>// store.js<br>import</strong> { createStore, combineReducers } from &quot;redux&quot;;<br><strong>import</strong> rootReducer from &quot;./reducers&quot;;<br><strong>import</strong> todoReducer from &#39;./reducers&#39;;</pre><pre><strong>export default</strong> createStore(combineReducers({<br>    root: rootReducer,<br>    todo: todoReducer<br>}));</pre><p>It is entirely possible for the reducer where the state mutation is defined to be connected to the store (might have another action defined in the reducer). This step is just for the case when the reducer file is a new one. Here, the todoReducer is where the DELETE_TODO action is defined is being connected to the store (<strong>Note: </strong>combineReducers() is merely a way to wrap all the reducers under a ‘master’ reducer of sorts and connecting that into the store).</p><h4>5. Pass the state/dispatchers to the container component</h4><pre><strong>import</strong> React from &quot;react&quot;;<br><strong>import</strong> { connect } from &quot;react-redux&quot;;<br><strong>import</strong> { addTodo, deleteTodo } from &#39;./todoActions.js&#39;;<br><strong>import</strong> Todo from &quot;./Todo&quot;;</pre><pre><strong>const</strong> TodoList = ({ todos }) =&gt; (<br>    ...<br>);<br><strong>const</strong> mapStateToProps = state =&gt; {<br>    ...<br>};<br><strong>const</strong> mapDispatchToProps = dispatch =&gt; {<br>    ...<br>    // add the deleteTodo() function as a prop</pre><pre>    deleteTodo: (id) =&gt; dispatch(deleteTodo(id))<br>}</pre><pre><strong>export default</strong> connect(mapStateToProps, mapDispatchToProps)(TodoList);</pre><p>Now that we have the action and reducer segment of the workflow complete, all that remains is the component segment. Now, we think along the lines of “okay, how do I ensure that my components have the ability to emit an action?” In this step, the TodoList component is the one that receives the ability to dispatch the DELETE_TODO action as a prop.</p><h4>6. Pass the state/dispatchers to the presentational component</h4><pre><strong>const</strong> TodoList = ({ todos }) =&gt; (<br>    &lt;<strong>ul</strong> className=&quot;todo-list&quot;&gt;<br>    ...<br>    &lt;Todo deleteTodo={this.props.deleteTodo} ... /&gt;;<br>    ...<br>    &lt;/<strong>ul</strong>&gt;<br>);</pre><p>All that remains is for us to pass the deleteTodo action (which was mapped to TodoList as a prop in Step 5) into the appropriate presentational component, which in this case is the Todo component. Here, each of the Todo component is given a deleteTodo prop which it can use to delete itself (yes its a poor choice of words but that’s how it works!)</p><h4>A Note on Steps 5 and 6</h4><p>A natural question that arises from the last two steps is why we didn’t connect the Todo component to the store and directly map the deleteTodo function as a prop. One of the most common architectural patterns in React is to separate components into presentational and container components, the properties of which are tabulated below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LynLyB01M51HYoRHicklAw.png" /></figure><p>Todo is a presentational component as it simply renders a Todo item, whereas TodoList is a container component designed to describe the workings of the todo list, which includes dispatching actions to add and remove todo items. This is why we take the pain of passing the deleteTodo function to the Todo components via the TodoList component.</p><p>If you want to understand the concept further, Dan Abramov has an excellent <a href="https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0">article</a> on it!</p><h3>Conclusion</h3><p>Writing high-performance web applications demands organization and mature architectural decisions, and part of that (in context of React) is ensuring that we don’t end up with ‘state spaghetti’ as the application grows.</p><blockquote>Writing high-performance web applications demands organization and mature architectural decisions, and part of that (in context of React) is ensuring that we don’t end up with ‘state spaghetti’ as the application grows.</blockquote><p>Yes, setting up Redux may be a pain initially due to the expensive overhead cost, but as the application grows and you add more and more functionality, keeping this checklist in mind will help ensure a streamlined development process!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=76088a9da634" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/a-helpful-checklist-while-adding-functionality-to-a-react-redux-app-76088a9da634">A Helpful Checklist While Adding Functionality to a React-Redux app</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[So why the heck are they called Support Vector Machines?]]></title>
            <link>https://medium.com/data-science/so-why-the-heck-are-they-called-support-vector-machines-52fc72c990a1?source=rss-296557a3927f------2</link>
            <guid isPermaLink="false">https://medium.com/p/52fc72c990a1</guid>
            <category><![CDATA[towards-data-science]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[support-vector-machine]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <dc:creator><![CDATA[Vidhur Kumar]]></dc:creator>
            <pubDate>Mon, 23 Mar 2020 21:23:15 GMT</pubDate>
            <atom:updated>2020-04-09T19:49:25.579Z</atom:updated>
            <content:encoded><![CDATA[<p>My first pass with Supervised Machine Learning was a quick one: I did some research on curriculums and handpicked the topics I wanted to learn. Then, I read a few articles on them until I understood the general concept (or I thought I did), experimented with them using the out-of-the-box Scikit-Learn version of the algorithm, and moved on. Recently, I began gaining a formal, in-depth knowledge of these supervised learning algorithms (the “why they work”, if you will). Naturally, SVMs were part of the fundamentals and it was then that I had an unsettling revelation: I had no idea what the words “Support Vector Machines” meant! I had completely overlooked the fact that this fancy name probably had a deeper meaning. In this piece, I summarize my findings and attempt to explain the mathematical reasoning behind this ‘complex’ name.</p><h3>The Shortcomings of the Perceptron Algorithm</h3><p>The Perceptron algorithm is a supervised learning algorithm for binary classification. Formally, it allows us to learn a binary classifier called a <strong>threshold function </strong>that allows us to map some <em>x</em> in <em>n-</em>dimensional space to an output value <em>f(x)</em><strong><em>, </em></strong>which is a binary value:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/916/1*jTUvf6prYRvzga0S5jRGfQ.png" /><figcaption>The binary classifier expressed as a piecewise function.</figcaption></figure><p>Note that the conditional expression for <em>f(x)</em> to be 1 contains a <strong>weighted </strong>summation in the form of a dot product <em>w ⋅ x</em> along with a <strong>bias</strong> added to it. A closer look tells us that we can rewrite the condition such that the bias represents the threshold value for our binary classifier:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/840/1*AQ5Vjys0Ao_8zsSUlKpA5g.png" /><figcaption>The binary classifier conditional rewritten to emphasize the bias as the threshold value mentioned above.</figcaption></figure><p>Note that the perceptron is a <strong>linear classifier</strong>, which means that if the training set <em>D</em> is not linearly separable, then no ‘approximate’ solution will be reached using the learning algorithm. However, if <em>D</em> is linearly separable then the algorithm is guaranteed to find a linear separator.</p><p>However, every dataset that is linearly separable admits <em>an infinite number of possible linear decision boundaries</em> that attains a misclassification rate of 0. The perceptron is assured to find one of these, but there is no guarantee as to how “good” this decision boundary is.</p><blockquote>Every dataset that is linearly separable admits <em>an </em><strong><em>infinite</em></strong><em> number of possible linear decision boundaries</em> that attains a misclassification rate of 0. The perceptron is assured to find one of these, but there is no guarantee as to how “good” this decision boundary is.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*WKE6xuPNucGNmr2uXGzVXw.png" /><figcaption>A binary classification problem in 2D space with an infinite number of decision boundaries that separate the classes. The Perceptron algorithm could produce any one of these decision boundaries.</figcaption></figure><h3>Maximum Margin Separators: The Case for SVMs</h3><p>This motivates us to come up with another algorithm that <strong>maximizes the margin </strong>between the two classes. The margin is defined as the <em>minimum distance between the data instances and the decision boundary.</em></p><p>Let the decision boundary be defined by the equation <em>w ⋅ x + b = 0. </em>In this case, <em>w</em> is the <em>n-</em>dimensional normal vector to the hyperplane. We normalize <em>w</em>, i.e., divide it by its length just in case its not a unit vector.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/574/1*U5DTPlRKSK8tUoSTP9k-_w.png" /><figcaption>The distance between the boundary and the training point closest to it from the positive class followed by the distance between the boundary and the training point closest to it from the negative class.</figcaption></figure><p>Let T be the set of <em>n</em> training instances that we are given. We need to find a vector <em>w</em> that maximizes the margin, which is given by:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/872/1*sKldh-e_h_rBc297G0gwMQ.png" /><figcaption>The maximum margin expressed mathematically. Notice that the equation inside the square brackets represents the distance between the point and the margin (the ‘y’ exists to differentiate between the positive and negative class). We define the margin in relation to the point closest to it from each class, which is why we minimize over all training examples.</figcaption></figure><h3>Formulating this as a Constrained Optimization Problem</h3><p>Consider the set of vectors <em>w</em> such that the following constraint holds:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/252/1*qiyyjocIQCRo9UahDKJNsg.png" /></figure><p>These vectors produce a linear separator that perfectly separates the data <strong>with a non-zero margin</strong>. It helps to introduce some equality into the above constraint and scale <em>w </em>to arrive at the following solution set <em>S</em>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/143/1*h8rMit99KGxIb12qVEEF-A.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/136/1*iOiC0uoFC6jekWa9T_Utpw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/286/1*osvP4WkNRvup0Yb_xaw0Pg.png" /></figure><p>If <em>D</em>=1, then</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/297/1*_uqRV-9daBxUi3nqukzJfg.png" /></figure><p>On the other hand, if <em>D &gt; </em>1, then</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/115/1*wwQ_neGLHpSyEiSgEzYyoQ.png" /></figure><p>Notice that if the closest point is more than a distance of 1 / ||<em>w</em>|| away from the separator, we can always adjust <em>w</em> to ensure that the distance is decreased. Thus, the quantity 1 / ||<em>w</em>|| is the margin, and we need to minimize ||<em>w</em>|| in order to maximize the margin. We have the following optimization problem:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/223/1*eCFolZRtyQlb1jD_-j6Tjw.png" /></figure><p>subject to the following constraints:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/321/1*M4K8n307-aykMtG2kn9s-Q.png" /></figure><p>Now that we have a mathematical framework to solve the problem, there is a caveat that we need to address: we have been operating under the assumption that the data we have is linearly separable. But what if it’s not? In that case, <em>S</em> would be empty and we’d be left with an infeasible solution. We can work around this by relaxing our constraints to the following:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/429/1*a_7FEiTDByR1q2SEO-8q5Q.png" /></figure><p>Of course, we keep the relaxation constant ϵ &gt; 0 but small enough so as to not overshoot and obtain a non-optimal solution. We rewrite our minimization problem to be:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/473/1*sBv3XblGM_HKaHxMjrYd_g.png" /></figure><p>The parameter <em>C</em> represents the tradeoff between minimizing the error and maximizing the margin. Solving this problem is done via <a href="https://en.wikipedia.org/wiki/Quadratic_programming">Quadratic Programming</a>.</p><h3>Enter Support Vectors</h3><p>The support vectors are the training instances that satisfy the constraint:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/564/1*x7m-NMy0tGfneeCuY7Tvpw.png" /><figcaption>The constraint that needs to be satisfied for a training instance to become a support vector.</figcaption></figure><p>The solution to our problem, i.e., the optimal (maximum-margin) hyperplane remains unchanged if we remove all training instances but the support vectors. That is why they are given the name ‘support vectors’. These training instances can be thought of as ‘supporting’ or ‘holding up’ the optimal hyperplane.</p><blockquote>That is why they are given the name ‘support vectors’. These training instances can be thought of as ‘supporting’ or ‘holding up’ the optimal hyperplane.</blockquote><h3>The Objective of Support Vector Machines</h3><p>So, what do SVMs do with the data we provide them? The objective is as follows:</p><blockquote>Assuming that each data point is <strong><em>n</em></strong><em>-</em>dimensional, a Support Vector Machine attempts to find the <strong><em>(n-1)-</em></strong>dimensional hyperplane <strong>of maximum margin.</strong></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*FGzasG-84SHk_XXSClcoqA.png" /></figure><p>Intuitively, this proves to be very effective in boosting the performance of the classifier/regressor as the larger margin, the lower the generalization error of the classifier/regressor.</p><h3>References</h3><p>“Large Margin Separators”: <a href="http://cs.brown.edu/people/pfelzens/engn2520/CS1420_Lecture_10.pdf">http://cs.brown.edu/people/pfelzens/engn2520/CS1420_Lecture_10.pdf</a></p><p>“Support Vector Machines”: <a href="https://en.wikipedia.org/wiki/Support-vector_machine">https://en.wikipedia.org/wiki/Support-vector_machine</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=52fc72c990a1" width="1" height="1" alt=""><hr><p><a href="https://medium.com/data-science/so-why-the-heck-are-they-called-support-vector-machines-52fc72c990a1">So why the heck are they called Support Vector Machines?</a> was originally published in <a href="https://medium.com/data-science">TDS Archive</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Classifying Loans based on the risk of defaulting]]></title>
            <link>https://medium.com/data-science/classifying-loans-based-on-the-risk-of-defaulting-using-logistic-regression-9bd9c6b44640?source=rss-296557a3927f------2</link>
            <guid isPermaLink="false">https://medium.com/p/9bd9c6b44640</guid>
            <category><![CDATA[classification-models]]></category>
            <category><![CDATA[classification]]></category>
            <category><![CDATA[classification-algorithms]]></category>
            <category><![CDATA[classification-problem]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Vidhur Kumar]]></dc:creator>
            <pubDate>Thu, 22 Aug 2019 07:03:08 GMT</pubDate>
            <atom:updated>2020-06-07T21:10:34.479Z</atom:updated>
            <content:encoded><![CDATA[<h3>A Short Introduction</h3><p>Classification is one of the classical problems in Supervised Learning where we attempt to train a model to classify data points into *<em>n</em>* distinct classes. As I was browsing through datasets online, I came across one that contained information on 1000 loan applicants (from both urban and rural areas). One of the columns in the data table was whether or not the loan was approved. An idea immediately struck me:</p><blockquote>What if we could build a model to predict whether an applicant’s loan would be approved or denied depending on his or her risk of defaulting?</blockquote><p>This would be a garden-variety classification problem, where we have 2 distinct classes to group our data by: a loan approval or a loan denial.</p><p>It is important to not be hasty and start training models on the raw and unexplored data. Preprocessing the data not only helps us smooth out inconsistencies (missing values and outliers), but also gives us a comprehensive understanding of the data which in turn aids us in our model selection process.</p><p>This end-to-end Machine Learning project is primarily based on Python. I have used the following libraries to help me achieve the objective:</p><p>1. <strong>Numpy </strong>for mathematical operations.</p><p>2. <strong>Pandas</strong> for data exploration and analysis</p><p>3. <strong>Matplotlib</strong> and <strong>Seaborn</strong> for data visualization</p><p>4. <strong>Scikit-learn</strong> for model training, cross-validation, and evaluation metrics.</p><h3>Importing the Libraries</h3><p>Let us perform all the necessary imports beforehand.</p><pre><strong>import</strong> <strong>numpy</strong> <strong>as</strong> np<br>np<strong>.</strong>seterr(divide<strong>=</strong>&#39;ignore&#39;)<br><strong>import</strong> <strong>math</strong><br><strong>import</strong> <strong>pandas</strong> <strong>as</strong> pd<br><strong>from</strong> <strong>sklearn.linear_model</strong> <strong>import</strong> LogisticRegression<br><strong>from</strong> <strong>sklearn.model_selection</strong> <strong>import</strong> train_test_split<br><strong>from</strong> <strong>sklearn.preprocessing</strong> <strong>import</strong> OneHotEncoder<br><strong>from</strong> <strong>sklearn</strong> <strong>import</strong> metrics<br><strong>import</strong> <strong>matplotlib.pyplot</strong> <strong>as</strong> plt<br><strong>import</strong> <strong>seaborn</strong> <strong>as</strong> sns</pre><p>Once we have all the libraries necessary, we can read the data in from CSV file using Pandas.</p><pre>data <strong>=</strong> pd<strong>.</strong>read_csv(&#39;credit_risk.csv&#39;)</pre><h3>Understanding the Features</h3><p>Before moving forward with the data exploration, I always like to understand the features that I will be dealing with on a superficial level. Doing this will help us put into words any mathematical interpretations we make. The following are the list of features that we have from our dataset:</p><ol><li><strong>Loan ID</strong>: The ID given by the bank to the loan request.</li><li><strong>Gender</strong>: The gender of the primary applicant.</li><li><strong>Married</strong>: Binary variable indicating the marital status of the primary applicant.</li><li><strong>Dependents</strong>: Number of dependents of the primary applicant.</li><li><strong>Education</strong>: Binary variable indicating whether or not the primary applicant has graduated high school.</li><li><strong>Self_Employed</strong>: Binary variable indicating whether or not the individual is self-employed.</li><li><strong>Applicant Income</strong>: The income of the primary applicant.</li><li><strong>Co-Applicant Income</strong>: The income of the co-applicant.</li><li><strong>Loan Amount</strong>: The amount the applicant wants to borrow.</li><li><strong>Loan Amount Term</strong>: The term over which the applicant would repay the loan.</li><li><strong>Credit History</strong>: Binary variable representing whether the client had a good history or a bad history.</li><li><strong>Property Area</strong>: Categorical variable indicating whether the applicant was from an urban, semiurban, or a rural area.</li><li><strong>Loan Status</strong>: Variable indicating whether the loan was approved or denied. This will be our output (dependent) variable.</li></ol><p>Of all these variables, I have chosen the Gender, Applicant Income, Loan Amount, and Property Area as the ones to delve deeper into. It is important to look at the data from multiple angles, i.e., independently and in relation to the other variables. This points out any red flags in the distributions of the variables and also reveals interesting relationships amongst them.</p><h3>Visualizing the data</h3><p>Humans are visual creatures, and a majority of us process information better when we see it. Thus, when it comes to understanding our data, taking a visual approach is far more effective than manually crunching hundreds of rows worth of numbers. I have plotted visualizations that show the distributions of important features as well as interesting relationships between some of the features. How did I decide which features are important? I used the correlation matrix, where the value at (i, j) represents how strongly <em>feature i</em> is correlated to <em>feature j</em>.</p><p>We can use seaborn’s heatmap visualization to help us understand the correlation matrix.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/524/1*AKBFnQ6D9UpG9-x7RsiMKQ.png" /><figcaption>The Correlation Matrix for the Dataset</figcaption></figure><pre>sns<strong>.</strong>heatmap(data<strong>.</strong>corr())</pre><p>Before we begin exploring our feature variables, I wanted to have a look at our dependent variable, i.e., the one we are attempting to predict using the model. Shown below is a simple countplot by class.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*szC-ySv0vrOGU62hqHj4CA.png" /><figcaption>A count of the two classes that we are attempting to predict</figcaption></figure><p>There is a clear imbalance between the classes, and that can be very dangerous! Our model may end up highly biased towards the majority class, which is not ideal when it comes to the model’s generalization capabilities. For that reason, we will perform feature scaling to ensure uniformity, and also make sure that the algorithm we use to build the model is ‘aware’ that the classes are imbalanced.</p><p>I was also curious about how the property area and the loan amount jointly affected the authorization of the loan. Let us have a look at a relational plot of the loan amount against approval separated by the property area.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*DtIb8CVIHXOHT5uIvXxnpQ.png" /><figcaption>A Scatter plot of Loan Amount against the Loan Status, color-coded by the Property Area</figcaption></figure><p>It will help if we divide the data into approved and unapproved loans and look at the count of how many of those loan applications came from each property area.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*LyG7I2fwOAGDSVN_MbOJCw.png" /><figcaption>A bar plot depicting the number of approved applicants from each property area</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*GalP__M8qfW89KQLsC3Vfg.png" /><figcaption>A bar plot depicting the number of unapproved applicants from each property area</figcaption></figure><p>From the looks of it, it looks like a higher fraction of the rural loan applications are denied. I calculated the ratio of approved loans from each property area, and the numbers corroborate our hypothesis.</p><ol><li><strong>Urban Approval Ratio: 0.7368421052631579</strong></li><li><strong>Semiurban Approval Ratio: 0.7822349570200573</strong></li><li><strong>Rural Approval Ratio: 0.6448275862068965</strong></li></ol><h3>Cleaning the data</h3><p>Now that we’ve explored the data visually to better understand what we’re dealing with, its time to preprocess our data in order to make sure that the model we train is not subject to any noisy training instances (in the context of ML, the term “training instance” refers to a single data point that is part of the dataset used to train and test the model.) I have divided our preprocessing step into the following substeps:</p><ol><li>Check for and replace missing values if necessary.</li><li>Remove unncessary features.</li><li>Encode categorical features to make sure they are properly interpreted.</li></ol><pre><em># Replace the categorical values with the numeric equivalents that we have above</em><br>categoricalFeatures <strong>=</strong> [&#39;Property_Area&#39;, &#39;Gender&#39;, &#39;Married&#39;, &#39;Dependents&#39;, &#39;Education&#39;, &#39;Self_Employed&#39;]<br><br><em># Iterate through the list of categorical features and one hot encode them.</em><br><strong>for</strong> feature <strong>in</strong> categoricalFeatures:<br>    onehot <strong>=</strong> pd<strong>.</strong>get_dummies(data[feature], prefix<strong>=</strong>feature)<br>    data <strong>=</strong> data<strong>.</strong>drop(feature, axis<strong>=</strong>1)<br>    data <strong>=</strong> data<strong>.</strong>join(onehot)</pre><p>Note that data preprocessing is by no means formulaic, and the steps that I am about to take are subjective.</p><h3>Training the model</h3><p>Finally, the exciting bit! We have our data prepared, and we shall serve it to our model to devour! The algorithm that I chose for this particular case was Logistic Regression. It is one of the simpler supervised learning algorithms but has proven to be extremely reliant in a variety of instances.</p><p>Before we train the model, we shall utilize Scikit-learn’s inbuilt train-test split module to randomly split our dataset into training and testing subsets. We shall split it according to the 80–20 rule (this seems an arbitrary and scientifically ungrounded choice, but it is known to “just work” when it comes to training models).</p><p>Let us begin by instantiating a Logistic Regression object (we will be using scikit-learn’s module) and split the dataset in the aforementioned way.</p><pre><em># Liblinear is a solver that is effective for relatively smaller datasets.</em><br>lr <strong>=</strong> LogisticRegression(solver<strong>=</strong>&#39;liblinear&#39;, class_weight<strong>=</strong>&#39;balanced&#39;)</pre><p>Notice that we specify that the weights of the classes in question have to be balanced. This ensures that the classes are appropriately weighted, thereby eliminating any bias created by an imbalance in the classes. If you are curious as to how the classes are weighted, <a href="https://chrisalbon.com/machine_learning/logistic_regression/handling_imbalanced_classes_in_logistic_regression/">this article by Chris Albon</a> provides a comprehensive explanation.</p><p>Before we pass in the data, let us perform feature scaling using Scikit-learn’s Standard Scaler.</p><pre>scaler <strong>=</strong> StandardScaler()<br>data_std <strong>=</strong> scaler<strong>.</strong>fit_transform(data)</pre><pre><em># We will follow an 80-20 split pattern for our training and test data</em><br>X_train,X_test,y_train,y_test <strong>=</strong> train_test_split(data, y, test_size<strong>=</strong>0.2, random_state <strong>=</strong> 0)</pre><p>Now that we have everything we need, we fit the model to the training data.</p><pre>lr<strong>.</strong>fit(X_train, y_train)</pre><h3>Evaluating the performance of the model</h3><p>It is just as (if not more) important to evaluate the performance of algorithms as it is understanding and implementing them. I’ve provided a brief but comprehensive introduction to the confusion matrix and the three fundamental evaluation metrics for classification.</p><p>A Confusion matrix is simply a tabular visualization of the error rates of the matrix that is widely used to evaluate the performance of a classification algorithm. The rows of the matrix represent the actual label of the instance, while the columns reprsent the predicted label. In our case, we have a 2x2 matrix as we are performing binary classification. To generalize, an “n-ary” classification problem will have an nxn confusion matrix.</p><p>The <em>(m, n)</em> entry of the confusion matrix tells us how many instances whose correct label is class <em>m</em> was classified into class <em>n</em>. So, the diagonal entries of our matrix represent correct classifications and the rest represent the incorrect ones. In binary classification, the diagonal entries are commonly referred to as the <strong>true positives</strong> and the <strong>true negatives</strong>, and the other two are the <strong>false positives</strong> and <strong>false negatives</strong>.</p><p>Now that the model has been trained, we will use the test data that we sieved from the original dataset to evaluate how well our model generalizes to the data. I have divided the evaluation process in the following way:</p><ol><li>Vectorize the predictions made by the model and build a confusion matrix.</li><li>Use the confusion matrix</li></ol><pre><em># We will compare this vector of predictions to the actual target vector to determine the model performance.</em><br>y_pred <strong>=</strong> lr<strong>.</strong>predict(X_test)<br><br><em># Build the confusion matrix.</em><br>confusion_matrix <strong>=</strong> metrics<strong>.</strong>confusion_matrix(y_test, y_pred)<br>class_names<strong>=</strong>[0,1] <em># name of classes</em><br>fig, ax <strong>=</strong> plt<strong>.</strong>subplots()<br>tick_marks <strong>=</strong> np<strong>.</strong>arange(len(class_names))<br>plt<strong>.</strong>xticks(tick_marks, class_names)<br>plt<strong>.</strong>yticks(tick_marks, class_names)<br><br><em># The heatmap requires that we pass in a dataframe as the argument</em><br>sns<strong>.</strong>heatmap(pd<strong>.</strong>DataFrame(confusion_matrix), annot<strong>=</strong>True, cmap<strong>=</strong>&quot;YlGnBu&quot;, fmt<strong>=</strong>&quot;g&quot;)<br><br><em># Configure the heatmap parameters</em><br>ax<strong>.</strong>xaxis<strong>.</strong>set_label_position(&quot;top&quot;)<br>plt<strong>.</strong>tight_layout()<br>plt<strong>.</strong>title(&#39;Confusion matrix&#39;, y<strong>=</strong>1.1)<br>plt<strong>.</strong>ylabel(&#39;Actual label&#39;)<br>plt<strong>.</strong>xlabel(&#39;Predicted label&#39;)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*XysbkxMud7Uhxtb4K-9KBg.png" /><figcaption>The Confusion Matrix for the Logistic Regression Classifier</figcaption></figure><p>At a glance, most of our classifications seem to be concentrated in the diagonal entries. An excellent start! Recall that we said the matrix gave us the error rates. But it&#39;s hard to gain a concrete numerical measure of the model’s performance from the matrix alone. Thus, we use the values from the matrix to compute the three fundamental classification performance measures: <strong>accuracy, precision, and recall</strong>.</p><p>Scikit-learn’s inbuilt metrics module lets us compute these metrics in a single line of code!</p><pre><em># Print out our performance metrics</em><br><strong>print</strong>(&quot;Accuracy:&quot;,metrics<strong>.</strong>accuracy_score(y_test, y_pred))<br><strong>print</strong>(&quot;Precision:&quot;,metrics<strong>.</strong>precision_score(y_test, y_pred, pos_label<strong>=</strong>&#39;Y&#39;))<br><strong>print</strong>(&quot;Recall:&quot;,metrics<strong>.</strong>recall_score(y_test, y_pred, pos_label<strong>=</strong>&#39;Y&#39;))</pre><p>For our model, the metrics’ values turned out to be:</p><ol><li><strong>Accuracy: 0.8116883116883117</strong></li><li><strong>Precision: 0.875</strong></li><li><strong>Recall: 0.8504672897196262</strong></li></ol><p>It is an accepted practice to use precision and recall in conjunction to gauge the performance of a classification model as one could simply use instances that he or she knows would result in a correct prediction to gain a perfect precision score. In other words, if I have one training instance that I knew belonged to the positive class I would make sure that the model classifies only that instance into the positive class. The F1 score is a metric that is a harmonic sum of the precision and recall. It is a singular measure of a model’s performance and takes into account both the precision and recall, thus making sure that we do not have to go through the hassle of interpreting the numbers manually. Yet again, Scikitl-learn’s metrics module comes to the rescue!</p><pre><strong>print</strong>(&quot;F1 Score:&quot;,metrics<strong>.</strong>f1_score(y_test, y_pred, pos_label<strong>=</strong>&#39;Y&#39;))</pre><p><strong>F1 Score: 0.8625592417061612</strong></p><h3>Conclusion</h3><p>Alright, awesome! We sucessfully trained a model that can predict the response to a loan applicant based on the data we have on them. To do this at scale would be futile for us humans, but the performance of the classifier shows us just how powerful these techniques can be. Classification is but one of the multitude of techniques available as part of the Predictive Modeling toolbox. I hope that this has proven to be an informative and engaging introduction to the topic.</p><p>Happy coding!</p><h3>Appendix</h3><p>Credit Risk Dataset: <a href="https://docs.google.com/spreadsheets/d/1em8nMTOH5_GpHVI_EowBkUjDViDTNc5YKbFUihjwk-g/edit?usp=sharing">https://docs.google.com/spreadsheets/d/1em8nMTOH5_GpHVI_EowBkUjDViDTNc5YKbFUihjwk-g/edit?usp=sharing</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9bd9c6b44640" width="1" height="1" alt=""><hr><p><a href="https://medium.com/data-science/classifying-loans-based-on-the-risk-of-defaulting-using-logistic-regression-9bd9c6b44640">Classifying Loans based on the risk of defaulting</a> was originally published in <a href="https://medium.com/data-science">TDS Archive</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>