<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://bendemra.ai/feed.xml" rel="self" type="application/atom+xml" /><link href="https://bendemra.ai/" rel="alternate" type="text/html" /><updated>2026-04-27T17:34:30+00:00</updated><id>https://bendemra.ai/feed.xml</id><title type="html">Hamza Bendemra</title><subtitle>GenAI &amp; Agentic AI</subtitle><entry><title type="html">Building an Employee Churn Model in Python to Develop a Strategic Retention Plan</title><link href="https://bendemra.ai/data-science/machine-learning/2019/03/11/building-employee-churn-model-python-strategic-retention-plan.html" rel="alternate" type="text/html" title="Building an Employee Churn Model in Python to Develop a Strategic Retention Plan" /><published>2019-03-11T06:00:00+00:00</published><updated>2019-03-11T06:00:00+00:00</updated><id>https://bendemra.ai/data-science/machine-learning/2019/03/11/building-employee-churn-model-python-strategic-retention-plan</id><content type="html" xml:base="https://bendemra.ai/data-science/machine-learning/2019/03/11/building-employee-churn-model-python-strategic-retention-plan.html"><![CDATA[<blockquote>
  <p><em>Originally published on <a href="https://medium.com/data-science/building-an-employee-churn-model-in-python-to-develop-a-strategic-retention-plan-57d5bd882c2d">Medium</a> on March 11, 2019</em></p>
</blockquote>

<p><img src="https://unsplash.com/photos/QBpZGqEMsKg/download?force=true&amp;w=800" alt="Employee working" />
<em>Everybody’s working hard but who is most likely to hand in their resignation letter? (Photo by Alex Kotliarskyi on Unsplash)</em></p>

<h1 id="contents">Contents</h1>

<ol>
  <li>Problem Definition</li>
  <li>Data Analysis</li>
  <li>EDA Concluding Remarks</li>
  <li>Pre-processing Pipeline</li>
  <li>Building Machine Learning Models</li>
  <li>Concluding Remarks</li>
</ol>

<h2 id="1-problem-definition">1. Problem Definition</h2>

<p>Employee turn-over (also known as “employee churn”) is a costly problem for companies. The true cost of replacing an employee can often be quite large.</p>

<p>A study by the <a href="https://www.americanprogress.org/wp-content/uploads/2012/11/CostofTurnover.pdf">Center for American Progress</a> found that companies typically pay about one-fifth of an employee’s salary to replace that employee, and the cost can significantly increase if executives or highest-paid employees are to be replaced.</p>

<p>In other words, the cost of replacing employees for most employers remains significant. This is due to the amount of time spent to interview and find a replacement, sign-on bonuses, and the loss of productivity for several months while the new employee gets accustomed to the new role.</p>

<p>Understanding why and when employees are most likely to leave can lead to actions to improve employee retention as well as possibly planning new hiring in advance. I will be using a step-by-step systematic approach using a method that could be used for a variety of ML problems. This project would fall under what is commonly known as HR Analytics or People Analytics.</p>

<p><img src="https://unsplash.com/photos/n95VMLxqM2I/download?force=true&amp;w=800" alt="Business meeting" />
<em>Ready to make data-driven decisions! (Photo by rawpixel on Unsplash)</em></p>

<p>In this study, we will attempt to solve the following problem statement:</p>

<p>• What is the likelihood of an active employee leaving the company?<br />
• What are the key indicators of an employee leaving the company?<br />
• What strategies can be adopted based on the results to improve employee retention?</p>

<p>Given that we have data on former employees, this is a standard supervised classification problem where the label is a binary variable, 0 (active employee), 1 (former employee). In this study, our target variable Y is the probability of an employee leaving the company.</p>

<p><strong>N.B.</strong> For complete code, please refer to this <a href="https://github.com/hamzaben86/Employee-Churn-Predictive-Model">GitHub repo</a> and/or the <a href="https://www.kaggle.com/hamzaben/employee-churn-model-w-strategic-retention-plan">Kaggle Kernel</a>.</p>

<h2 id="2-data-analysis">2. Data Analysis</h2>

<p>In this case study, a HR dataset was sourced from <a href="https://www.ibm.com/communities/analytics/watson-analytics-blog/hr-employee-attrition/">IBM HR Analytics Employee Attrition &amp; Performance</a> which contains employee data for 1,470 employees with various information about the employees. I will use this dataset to predict when employees are going to quit by understanding the main drivers of employee churn.</p>

<p>As stated on the <a href="https://www.ibm.com/communities/analytics/watson-analytics-blog/hr-employee-attrition/">IBM website</a>: “This is a fictional data set created by IBM data scientists. Its main purpose was to demonstrate the IBM Watson Analytics tool for employee attrition.”</p>

<p><img src="https://miro.medium.com/v2/resize:fit:4800/format:webp/1*yuiZeZzWBJPa1c7qLHRxhw.jpeg" alt="Data analysis" />
<em>Let’s crunch some employee data! (Photo by rawpixel on Unsplash)</em></p>

<h3 id="21-data-description-and-exploratory-visualisations">2.1 Data Description and Exploratory Visualisations</h3>

<p>First, we import the dataset and make of a copy of the source file for this analysis. The dataset contains 1,470 rows and 35 columns.</p>

<p>The dataset contains several numerical and categorical columns providing various information on employee’s personal and employment details.</p>

<h3 id="22-data-source">2.2 Data source</h3>

<p>The data provided has no missing values. In HR Analytics, employee data is unlikely to feature large ratio of missing values as HR Departments typically have all personal and employment data on-file.</p>

<p>However, the type of documentation data is being kept in (i.e. whether it is paper-based, Excel spreadsheets, databases, etc) has a massive impact on the accuracy and the ease of access to the HR data.</p>

<h3 id="23-numerical-features-overview">2.3 Numerical features overview</h3>

<p>A few observations can be made based on the information and histograms for numerical features:</p>

<p>• Several numerical features are tail-heavy; indeed several distributions are right-skewed (e.g. MonthlyIncome DistanceFromHome, YearsAtCompany). Data transformation methods may be required to approach a normal distribution prior to fitting a model to the data.<br />
• Age distribution is a slightly right-skewed normal distribution with the bulk of the staff between 25 and 45 years old.<br />
• EmployeeCount and StandardHours are constant values for all employees. They’re likely to be redundant features.<br />
• Employee Number is likely to be a unique identifier for employees given the feature’s quasi-uniform distribution.</p>

<h3 id="24-feature-distribution-by-target-attribute">2.4 Feature distribution by target attribute</h3>

<p>In this section, a more detailed Exploratory Data Analysis is performed. For complete code, please refer to this <a href="https://github.com/hamzaben86/Employee-Churn-Predictive-Model">GitHub repo</a> and/or the <a href="https://www.kaggle.com/hamzaben/employee-churn-model-w-strategic-retention-plan">Kaggle Kernel</a>.</p>

<p><strong>2.4.1 Age</strong></p>

<p>The age distributions for Active and Ex-employees only differs by one year; with the average age of ex-employees at 33.6 years old and 37.6 years old for current employees.</p>

<p><strong>2.4.2 Gender</strong></p>

<p>Gender distribution shows that the dataset features a higher relative proportion of male ex-employees than female ex-employees, with normalised gender distribution of ex-employees in the dataset at 17.0% for Males and 14.8% for Females.</p>

<p><strong>2.4.3 Marital Status</strong></p>

<p>The dataset features three marital status: Married (673 employees), Single (470 employees), Divorced (327 employees). Single employees show the largest proportion of leavers at 25%.</p>

<p><strong>2.4.4 Role and Work Conditions</strong></p>

<p>A preliminary look at the relationship between Business Travel frequency and Attrition Status shows that there is a largest normalized proportion of Leavers for employees that travel “frequently”. Travel metrics associated with Business Travel status were not disclosed (i.e. how many hours of Travel is considered “Frequent”).</p>

<p>Several Job Roles are listed in the dataset: Sales Executive, Research Scientist, Laboratory Technician, Manufacturing Director, Healthcare Representative, Manager, Sales Representative, Research Director, Human Resources.</p>

<p><strong>2.4.5 Years at the Company and Since Last Promotion</strong></p>

<p>The average number of years at the company for currently active employees is 7.37 years and ex-employees is 5.13 years.</p>

<p><strong>2.4.6 Years with Current Manager</strong></p>

<p>The average number of years with current manager for currently active employees is 4.37 years and ex-employees is 2.85 years.</p>

<p><strong>2.4.7 Overtime</strong></p>

<p>Some employees have overtime commitments. The data clearly show that there is significant larger portion of employees with OT that have left the company.</p>

<p><strong>2.4.8 Monthly Income</strong></p>

<p>Employee Monthly Income varies from $1009 to $19999.</p>

<p><strong>2.4.9 Target Variable: Attrition</strong></p>

<p>The feature “Attrition” is what this Machine Learning problem is about. We are trying to predict the value of the feature ‘Attrition’ by using other related features associated with the employee’s personal and professional history.</p>

<p>In the supplied dataset, the percentage of Current Employees is 83.9% and of Ex-employees is 16.1%. Hence, this is an imbalanced class problem.</p>

<p>Machine learning algorithms typically work best when the number of instances of each classes are roughly equal. We will have to address this target feature imbalance prior to implementing our Machine Learning algorithms.</p>

<h3 id="25-correlation">2.5 Correlation</h3>

<p>Let’s take a look at some of most significant correlations. It is worth remembering that correlation coefficients only measure linear correlations.</p>

<p>As shown above, “Monthly Rate”, “Number of Companies Worked” and “Distance From Home” are positively correlated to Attrition; while “Total Working Years”, “Job Level”, and “Years In Current Role” are negatively correlated to Attrition.</p>

<h2 id="3-eda-concluding-remarks">3. EDA Concluding Remarks</h2>

<p>• The dataset does not feature any missing or erroneous data values, and all features are of the correct data type.<br />
• The strongest positive correlations with the target features are: Performance Rating, Monthly Rate, Num Companies Worked, Distance From Home.<br />
• The strongest negative correlations with the target features are: Total Working Years, Job Level, Years In Current Role, and Monthly Income.<br />
• The dataset is imbalanced with the majority of observations describing Currently Active Employees.<br />
• Single employees show the largest proportion of leavers, compared to Married and Divorced counterparts.<br />
• About 10% of leavers left when they reach their 2-year anniversary at the company.<br />
• People who live further away from their work show higher proportion of leavers compared to their counterparts.<br />
• People who travel frequently show higher proportion of leavers compared to their counterparts.<br />
• People who have to work overtime show higher proportion of leavers compared to their counterparts.<br />
• Employees that have already worked at several companies previously (already “bounced” between workplaces) show higher proportion of leavers compared to their counterparts.</p>

<h2 id="4-pre-processing-pipeline">4. Pre-processing Pipeline</h2>

<p>In this section, we undertake data pre-processing steps to prepare the datasets for Machine Learning algorithm implementation. For complete code, please refer to this <a href="https://github.com/hamzaben86/Employee-Churn-Predictive-Model">GitHub repo</a> and/or the <a href="https://www.kaggle.com/hamzaben/employee-churn-model-w-strategic-retention-plan">Kaggle Kernel</a>.</p>

<h3 id="41-encoding">4.1 Encoding</h3>

<p>Machine Learning algorithms can typically only have numerical values as their predictor variables. Hence Label Encoding becomes necessary as they encode categorical labels with numerical values. To avoid introducing feature importance for categorical features with large numbers of unique values, we will use both Label Encoding and One-Hot Encoding as shown below.</p>

<h3 id="42-feature-scaling">4.2 Feature Scaling</h3>

<p>Feature Scaling using MinMaxScaler essentially shrinks the range such that the range is now between 0 and n. Machine Learning algorithms perform better when input numerical variables fall within a similar scale. In this case, we are scaling between 0 and 5.</p>

<h3 id="43-splitting-data-into-training-and-testing-sets">4.3 Splitting data into training and testing sets</h3>

<p>Prior to implementation or applying any Machine Learning algorithms, we must decouple training and testing dataframe from our master dataset.</p>

<h2 id="5-building-machine-learning-models">5. Building Machine Learning Models</h2>

<h3 id="51-baseline-algorithms">5.1 Baseline Algorithms</h3>

<p>Let’s first use a range of baseline algorithms (using out-of-the-box hyper-parameters) before we move on to more sophisticated solutions. The algorithms considered in this section are: Logistic Regression, Random Forest, SVM, KNN, Decision Tree Classifier, Gaussian NB.</p>

<p>Let’s evaluate each model in turn and provide accuracy and standard deviation scores. For complete code, please refer to this <a href="https://github.com/hamzaben86/Employee-Churn-Predictive-Model">GitHub repo</a> and/or the <a href="https://www.kaggle.com/hamzaben/employee-churn-model-w-strategic-retention-plan">Kaggle Kernel</a>.</p>

<p>Classification Accuracy is the number of correct predictions made as a ratio of all predictions made. It is the most common evaluation metric for classification problems.</p>

<p>However, it is often misused as it is only really suitable when there are an equal number of observations in each class and all predictions and prediction errors are equally important. It is not the case in this project, so a different scoring metric may be more suitable.</p>

<p>Area under ROC Curve (or AUC for short) is a performance metric for binary classification problems. The AUC represents a model’s ability to discriminate between positive and negative classes, and is better suited to this project. An area of 1.0 represents a model that made all predictions perfectly. An area of 0.5 represents a model as good as random.</p>

<p>Based on our ROC AUC comparison analysis, Logistic Regression and Random Forest show the highest mean AUC scores. We will shortlist these two algorithms for further analysis.</p>

<h3 id="52-logistic-regression">5.2 Logistic Regression</h3>

<p>GridSearchCV allows use to fine-tune hyper-parameters by searching over specified parameter values for an estimator. As shown below, the results from GridSearchCV provided us with fine-tuned hyper-parameter using ROC_AUC as the scoring metric.</p>

<h3 id="53-confusion-matrix">5.3 Confusion Matrix</h3>

<p>The Confusion matrix provides us with a much more detailed representation of the accuracy score and of what’s going on with our labels — we know exactly which/how labels were correctly and incorrectly predicted. The accuracy of the Logistic Regression Classifier on test set is 75.54.</p>

<h3 id="54-label-probability">5.4 Label Probability</h3>

<p>Instead of getting binary estimated target features (0 or 1), a probability can be associated with the predicted target. The output provides a first index referring to the probability that the data belong to class 0 (employee not leaving), and the second refers to the probability that the data belong to class 1 (employee leaving). Predicting probabilities of a particular label provides us with a measure of how likely an employee is to leave the company.</p>

<h3 id="55-random-forest-classifier">5.5 Random Forest Classifier</h3>

<p>Let’s take a closer look at using the Random Forest algorithm. I’ll fine-tune the Random Forest algorithm’s hyper-parameters by cross-validation against the AUC score.</p>

<p>Random Forest allows us to know which features are of the most importance in predicting the target feature (“Attrition” in this project). Below, we plot features by their importance.</p>

<p>Random Forest helped us identify the Top 10 most important indicators (ranked in the table below) as: (1) MonthlyIncome, (2) OverTime, (3) Age, (4) MonthlyRate, (5) DistanceFromHome, (6) DailyRate, (7) TotalWorkingYears, (8) YearsAtCompany, (9) HourlyRate, (10) YearsWithCurrManager.</p>

<p>The accuracy of the RandomForest Regression Classifier on test set is 86.14. Below the corresponding Confusion Matrix is shown.</p>

<p>Predicting probabilities of a particular label provides us with a measure of how likely an employee is to leave the company. The AUC when predicting probabilities using RandomForestClassifier is 0.818.</p>

<h3 id="56-roc-graphs">5.6 ROC Graphs</h3>

<p>AUC — ROC curve is a performance measurement for classification problem at various thresholds settings. ROC is a probability curve and AUC represents degree or measure of separability. It tells how much model is capable of distinguishing between classes. The green line represents the ROC curve of a purely random classifier; a good classifier stays as far away from that line as possible (toward the top-left corner).</p>

<p>As shown above, the fine-tuned Logistic Regression model showed a higher AUC score compared to the Random Forest Classifier.</p>

<h2 id="6-concluding-remarks">6. Concluding Remarks</h2>

<h3 id="61-risk-score">6.1 Risk Score</h3>

<p>As the company generates more data on its employees (on New Joiners and recent Leavers) the algorithm can be re-trained using the additional data and theoretically generate more accurate predictions to identify high-risk employees of leaving based on the probabilistic label assigned to each feature variable (i.e. employee) by the algorithm.</p>

<p>Employees can be assigning a “Risk Score” based on the predicted label such that:</p>

<p>• Low-risk for employees with label &lt; 0.6<br />
• Medium-risk for employees with label between 0.6 and 0.8<br />
• High-risk for employees with label &gt; 0.8</p>

<h3 id="62-indicators-and-strategic-retention-plan">6.2 Indicators and Strategic Retention Plan</h3>

<p>The stronger indicators of people leaving include:</p>

<p>• <strong>Monthly Income</strong>: people on higher wages are less likely to leave the company. Hence, efforts should be made to gather information on industry benchmarks in the current local market to determine if the company is providing competitive wages.<br />
• <strong>Over Time</strong>: people who work overtime are more likely to leave the company. Hence efforts must be taken to appropriately scope projects upfront with adequate support and manpower so as to reduce the use of overtime.<br />
• <strong>Age</strong>: Employees in relatively young age bracket 25–35 are more likely to leave. Hence, efforts should be made to clearly articulate the long-term vision of the company and young employees fit in that vision, as well as provide incentives in the form of clear paths to promotion for instance.<br />
• <strong>DistanceFromHome</strong>: Employees who live further from home are more likely to leave the company. Hence, efforts should be made to provide support in the form of company transportation for clusters of employees leaving the same area, or in the form of Transportation Allowance. Initial screening of employees based on their home location is probably not recommended as it would be regarded as a form of discrimination as long as employees make it to work on time every day.<br />
• <strong>TotalWorkingYears</strong>: The more experienced employees are less likely to leave. Employees who have between 5–8 years of experience should be identified as potentially having a higher-risk of leaving.<br />
• <strong>YearsAtCompany</strong>: Loyal companies are less likely to leave. Employees who hit their two-year anniversary should be identified as potentially having a higher-risk of leaving.<br />
• <strong>YearsWithCurrManager</strong>: A large number of leavers leave 6 months after their Current Managers. By using Line Manager details for each employee, one can determine which Manager have experienced the largest numbers of employees resigning over the past year.</p>

<p>Several metrics can be used here to determine whether action should be taken with a Line Manager:</p>

<p>• # of years the Line Manager has been in a particular position: this may indicate that the employees may need management training or be assigned a mentor (ideally an Executive) in the organisation<br />
• Patterns in the employees who have resigned: this may indicate recurring patterns in employees leaving in which case action may be taken accordingly.</p>

<h3 id="63-final-thoughts">6.3 Final Thoughts</h3>

<p>A strategic retention plan can be drawn for each Risk Score group. In addition to the suggested steps for each feature listed above, face-to-face meetings between a HR representative and employees can be initiated for medium- and high-risk employees to discuss work conditions. Also, a meeting with those employee’s Line Manager would allow to discuss the work environment within the team and whether steps can be taken to improve it.</p>

<hr />

<p>I hope you enjoyed reading this article as much as I had writing it. Once again, for complete code, please refer to this <a href="https://github.com/hamzaben86/Employee-Churn-Predictive-Model">GitHub repo</a> and/or the <a href="https://www.kaggle.com/hamzaben/employee-churn-model-w-strategic-retention-plan">Kaggle Kernel</a>.</p>]]></content><author><name></name></author><category term="data-science" /><category term="machine-learning" /><category term="machine-learning" /><category term="hr" /><category term="data-science" /><category term="people-analytics" /><category term="python" /><category term="employee-churn" /><category term="predictive-modeling" /><summary type="html"><![CDATA[A comprehensive guide to building machine learning models for predicting employee churn, featuring exploratory data analysis, model comparison, and strategic retention recommendations.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://bendemra.ai/assets/images/posts/employee-churn-model.jpg" /><media:content medium="image" url="https://bendemra.ai/assets/images/posts/employee-churn-model.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Soft Skills Will Make or Break You as a Data Scientist</title><link href="https://bendemra.ai/data-science/career-advice/2019/01/12/soft-skills-will-make-or-break-you-as-a-data-scientist.html" rel="alternate" type="text/html" title="Soft Skills Will Make or Break You as a Data Scientist" /><published>2019-01-12T06:00:00+00:00</published><updated>2019-01-12T06:00:00+00:00</updated><id>https://bendemra.ai/data-science/career-advice/2019/01/12/soft-skills-will-make-or-break-you-as-a-data-scientist</id><content type="html" xml:base="https://bendemra.ai/data-science/career-advice/2019/01/12/soft-skills-will-make-or-break-you-as-a-data-scientist.html"><![CDATA[<blockquote>
  <p><em>Originally published on <a href="https://medium.com/data-science/soft-skills-will-make-or-break-you-as-a-data-scientist-7b9c8c47f9b">Medium</a> on January 12, 2019</em></p>
</blockquote>

<p><img src="https://unsplash.com/photos/zEIC764gb9w/download?force=true&amp;w=800" alt="Office meeting discussion" />
<em>“What do you mean you can’t give me a definitive yes or no answer?” (Photo by rawpixel on Unsplash)</em></p>

<p>As businesses gather an increasing amount of data related to various aspects of their organisation (e.g. internal business operations, customer purchases and behaviour), the demand for data-savvy employees has exploded over the last 5 years.</p>

<p>Business leaders have woken up to the fact that data-driven decision-making can lead to making better decisions (it is not the only factor of course, but that’s a discussion for another post). As a result, there is a strong demand for data analysts and data scientists across a wide range of industries.</p>

<p>Since HBR’s declaration that Data Scientist is the “Sexiest Job of the 21st Century” back in 2012, a plethora of online and university courses have flourished to allow interested students to learn the fundamentals of Data Science. However, there are several key aspects that deserve more attention than they get in the current discussion to ensure your long-term success as a Data Scientist. In this post, I will focus on two:</p>

<h2 id="1-there-is-no-such-thing-as-a-typical-data-scientist-experience">1. There is no such thing as a “typical” Data Scientist experience.</h2>

<p>Your journey and work experience as a Data Scientist will massively vary depending on the culture and data maturity level of the organisation you work at.</p>

<p><img src="https://unsplash.com/photos/V9sv7QrDUgc/download?force=true&amp;w=800" alt="Programming workspace" />
<em>Your data science journey will vary greatly depending on your organization’s maturity (Photo by Jefferson Santos on Unsplash)</em></p>

<p>You may spend the first few weeks or months mostly working as a Data Engineer setting up databases, and determining which data infrastructure would be most suitable for the organisation.</p>

<p>After this initial stage, then you may mostly worked as a Data Analyst spending your days writing Python scripts and SQL queries to organise, clean the various datasets collected, and set up automated data pipelines to automate data collection, cleaning, and processing.</p>

<p>After the foundations are built, then will you I start analysing structured and unstructured data to identify trends and patterns using statistical and ML models. Finally, you’ll be able to work as a Data Scientist and built various predictive, classification, and forecasting models.</p>

<p>Now, being able to get to this final stage can take a lot of negotiation and convincing, primarily to buy time to set things up before being able to provide valuable action-oriented insights. The truth is that all the hype surrounding AI is the best and worst thing that’s happened to it.</p>

<blockquote>
  <p>All the hype surrounding Machine/Deep Learning is the best and worst thing that’s happened to it.</p>
</blockquote>

<p>It has increased interest (and funding) in the field but it has also created unreasonable expectations when applied in a business context. It has reduced the work that we do as Expert Statisticians with Strong Programming Skills (isn’t that what a Data Scientist is?) to a string of buzzwords and headlines.</p>

<p>This has created an environment where businesses expect outcomes right away. This is particularly the case if they don’t have an existing data infrastructure as they would often not know the preliminary groundwork that it takes, and I don’t blame them: you don’t know what you don’t know — that’s why you hire a data-savvy employee. Which brings me to my second point.</p>

<h2 id="2-your-soft-skills-will-make-or-break-you-as-a-data-scientist">2. Your soft skills will make or break you as a Data Scientist</h2>

<p>Your ability to communicate the value and insights that can be derived from your work is key to your long-term success as a Data Scientist. You need to get C-level staff on board as you need data-driven leadership. Your skills in presenting yourself and in articulating the value of your work will help you in hiring new employees and build your data-driven team.</p>

<p>Slowly, the results you are contributing to coupled with your ability to articulate the process and value of your work, will snowball and create interest in the rest of the organisation. Take this opportunity to up-skill current employees who are interested in learning more, and create allies of your Data Science team in other departments of the organisation.</p>

<p><img src="https://unsplash.com/photos/gMsnXqILjp4/download?force=true&amp;w=800" alt="Business presentation" />
<em>Effective communication is crucial for data science success (Photo by Campaign Creators on Unsplash)</em></p>

<p>Written and oral communication skills such as the ability to prepare progress reports, presentations, and interactive data dashboards to communicate findings and insights to key stakeholders will increase the actual and perceived value you provide to the business.</p>

<p>You must be able to translate your findings into business decisions by also providing brief non-technical background on the techniques you used and the biases and uncertainties inherent to the data science process.</p>

<p>Ultimately, in a business context, the best algorithm is not the one with the highest AUC score, it is the one that the stakeholders understand and trust enough to agree to use it effectively.</p>

<p>Building these soft skills alongside strong technical skills is no trivial feat and this is why skilled data scientists are so hard to find and so much sought-after.</p>

<p>But getting the skills to be a full-stack data scientist with strong communication skills is something that can be developed over time and should not be dismissed as optional.</p>

<hr />

<p><em>If you found this article helpful, feel free to connect with me on <a href="https://linkedin.com/in/hamzabendemra" target="_blank" rel="noopener">LinkedIn</a> or check out my other articles on <a href="https://medium.com/@Hamza.b86" target="_blank" rel="noopener">Medium</a>.</em></p>]]></content><author><name></name></author><category term="data-science" /><category term="career-advice" /><category term="data-science" /><category term="communication" /><category term="soft-skills" /><category term="career" /><category term="machine-learning" /><category term="business" /><summary type="html"><![CDATA[Essential insights on why soft skills are crucial for data scientists, covering communication, stakeholder management, and building successful data-driven teams in business environments.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://bendemra.ai/assets/images/posts/soft-skills-data-scientist.jpg" /><media:content medium="image" url="https://bendemra.ai/assets/images/posts/soft-skills-data-scientist.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Using Unsupervised Learning to Plan a Vacation to Paris: Geo-location Clustering</title><link href="https://bendemra.ai/data-science/machine-learning/2018/05/22/using-unsupervised-learning-to-plan-a-paris-vacation-geo-location-clustering.html" rel="alternate" type="text/html" title="Using Unsupervised Learning to Plan a Vacation to Paris: Geo-location Clustering" /><published>2018-05-22T06:00:00+00:00</published><updated>2018-05-22T06:00:00+00:00</updated><id>https://bendemra.ai/data-science/machine-learning/2018/05/22/using-unsupervised-learning-to-plan-a-paris-vacation-geo-location-clustering</id><content type="html" xml:base="https://bendemra.ai/data-science/machine-learning/2018/05/22/using-unsupervised-learning-to-plan-a-paris-vacation-geo-location-clustering.html"><![CDATA[<blockquote>
  <p><em>Originally published on <a href="https://medium.com/data-science/using-unsupervised-learning-to-plan-a-paris-vacation-geo-location-clustering-d0337b4210de">Medium</a> on May 22, 2018</em></p>
</blockquote>

<p><img src="https://unsplash.com/photos/Q0-fOL2nqZc/download?force=true&amp;w=800" alt="Eiffel Tower Paris" />
<em>The Eiffel Tower in the City of Love but there are so many great sights in Paris — how can I help her organise her trip?</em></p>

<p>When my friend told me she was planning a 10-day trip to Paris, I figured I could help.</p>

<blockquote>
  <p><strong>Her</strong>: “My friend and I are thinking of going to Paris on vacation.”<br />
<strong>Me</strong>: “Oh sounds fun. Maybe I can join in as well.”<br />
<strong>Her</strong>: “Yes! We’re planning to enrol in a French language course, and do loads of shopping! We already listed all the shopping malls we want to visit, and …”<br />
<strong>Me</strong>: “Ah sounds great… so what time do you need me to drive you to the airport?”</p>
</blockquote>

<p>Since I’ve been to Paris a few times myself, I figured I could help in other ways like contributing to the list of sights and places to visit. After listing all those sights and attractions, I created a Google map with a pin for each location.</p>

<p><img src="https://unsplash.com/photos/dC6Pb2JdAqs/download?force=true&amp;w=800" alt="Google Maps with pins" />
<em>The initial Google Map with pins for sights to visit — but in what order should these sights be visited?</em></p>

<p>It became quite clear that some scheduling work would be needed to see all that Paris had to offer — but how can she decide what to see first, and in what order? This seemed to me like a <a href="https://towardsdatascience.com/tagged/clustering">clustering</a> problem to me and <a href="https://towardsdatascience.com/tagged/unsupervised-learning">unsupervised learning</a> method could help solve it.</p>

<p>Algorithms like <a href="http://scikit-learn.org/stable/modules/clustering.html#k-means">K-Means</a>, or <a href="http://scikit-learn.org/stable/modules/clustering.html#dbscan">DBScan</a> would probably do the trick. But first, the data must prepared to facilitate for such algorithm to perform as intended.</p>

<h2 id="geolocations-collection-and-data-preparation">Geolocations Collection and Data Preparation</h2>

<p>First, I had to gather the Google map pins geo-locations in a 2D format (something that could be stored in a <a href="https://docs.scipy.org/doc/numpy/reference/generated/numpy.array.html">numpy array</a>). Translating those pins into [longitude, latitude] would be perfect.</p>

<p>Since this was a one-off, I looked for a quick way to extract this info from the Google map. This <a href="https://stackoverflow.com/questions/2558016/how-to-extract-the-lat-lng-of-pins-in-google-maps">StackOverflow query</a> gave me all that I needed.</p>

<p>Basically, one needs to go to google.com/maps/d/kml?mid={map_id} and download a *.kmz file. Then, manually change the extension of the *.kmz file to a *.zip file. Extract the file, and open doc.kml in a text editor of your choice (<a href="https://www.sublimetext.com/">SublimeText</a> is my personal go-to).</p>

<p>Then, you may decide to manually CTRL+F to search for <code class="language-plaintext highlighter-rouge">&lt;coordinates&gt;</code> fields, or decide to not be so lazy about it and use <a href="https://www.crummy.com/software/BeautifulSoup/">BeautifulSoup</a> (as shown below)!</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">bs4</span> <span class="kn">import</span> <span class="n">BeautifulSoup</span>

<span class="c1"># Parse the KML file
</span><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">'doc.kml'</span><span class="p">,</span> <span class="s">'r'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
    <span class="n">soup</span> <span class="o">=</span> <span class="n">BeautifulSoup</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="s">'xml'</span><span class="p">)</span>

<span class="c1"># Extract coordinates
</span><span class="n">coordinates</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">placemark</span> <span class="ow">in</span> <span class="n">soup</span><span class="p">.</span><span class="n">find_all</span><span class="p">(</span><span class="s">'Placemark'</span><span class="p">):</span>
    <span class="n">coords</span> <span class="o">=</span> <span class="n">placemark</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="s">'coordinates'</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">coords</span><span class="p">:</span>
        <span class="n">coordinates</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">coords</span><span class="p">.</span><span class="n">text</span><span class="p">.</span><span class="n">strip</span><span class="p">())</span>
</code></pre></div></div>

<p>Once I extracted the coordinates from the XML file, I stored the coordinates in a dataframe. The total number of landmarks is 26 (stored in <code class="language-plaintext highlighter-rouge">&lt;Placemark&gt;&lt;/Placemark&gt;</code> in the XML file).</p>

<p><img src="https://unsplash.com/photos/JKUTrJ4vK00/download?force=true&amp;w=800" alt="Data analysis visualization" />
<em>Dataframe populated with info from the XML file (first 7 rows only shown)</em></p>

<p>From the dataframe which stored coordinates and the name of the landmark/sight, I generated a scatter plot.</p>

<h2 id="k-means-clustering">K-Means Clustering</h2>

<p>In general, unsupervised learning methods are useful for datasets without labels AND when we do not necessarily know the outcome we are trying the predict. These algorithms typically take one of two forms: (1) clustering algorithms, or (2) dimensionality reduction algorithms.</p>

<p>In this section, we’ll focus on <a href="https://en.wikipedia.org/wiki/K-means_clustering">k-means</a>, which is a clustering algorithm. With k-means, a pre-determined number of clusters is provided as input and the algorithm generates the clusters within the un-labeled dataset.</p>

<p>k-means generates a set of k cluster centroids and a labeling of input array X that assigns each of the points in X to a unique cluster. The algorithm determines cluster centroids as the arithmetic mean of all the points belonging to the cluster, AND defines clusters such that each point in the dataset is closer to its own cluster center than to other cluster centers.</p>

<p>It can be implemented in Python using <a href="http://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html">sklearn</a> as follows:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">sklearn.cluster</span> <span class="kn">import</span> <span class="n">KMeans</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>

<span class="c1"># Prepare coordinates array
</span><span class="n">coordinates_array</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([[</span><span class="n">lat</span><span class="p">,</span> <span class="n">lng</span><span class="p">]</span> <span class="k">for</span> <span class="n">lat</span><span class="p">,</span> <span class="n">lng</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">df</span><span class="p">[</span><span class="s">'Latitude'</span><span class="p">],</span> <span class="n">df</span><span class="p">[</span><span class="s">'Longitude'</span><span class="p">])])</span>

<span class="c1"># Apply K-Means clustering
</span><span class="n">kmeans</span> <span class="o">=</span> <span class="n">KMeans</span><span class="p">(</span><span class="n">n_clusters</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">random_state</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span>
<span class="n">cluster_labels</span> <span class="o">=</span> <span class="n">kmeans</span><span class="p">.</span><span class="n">fit_predict</span><span class="p">(</span><span class="n">coordinates_array</span><span class="p">)</span>

<span class="c1"># Add cluster labels to dataframe
</span><span class="n">df</span><span class="p">[</span><span class="s">'Cluster'</span><span class="p">]</span> <span class="o">=</span> <span class="n">cluster_labels</span>
</code></pre></div></div>

<p>As one can see in the scatter plot below, I generated 10 clusters — one for each vacation day. But the sights in the center of Paris are so close to each other, it is quite difficult to distinguish one cluster from the other. The resulting predictions were also sorted and stored in a dataframe.</p>

<p>Using the 10 clusters generated by k-means, I generated a dataframe that assigns a day of the week to each cluster. This would constitute an example of a schedule.</p>

<p>Now, at this stage, I could have simply handed over the sorted dataframe, re-organised the Google map <a href="https://support.google.com/mymaps/answer/3024933?co=GENIE.Platform%3DDesktop&amp;hl=en">pins by layers</a> (i.e. each layer representing one day), and that’s it — itinerary complete.</p>

<p>But something was still bugging me, and that is that k-means was generating clusters based on the Euclidean distance between points — meaning the straight-line distance between two pins in the map.</p>

<p>But as we know, the Earth isn’t flat (<a href="http://theconversation.com/how-to-reason-with-flat-earthers-it-may-not-help-though-95160">right?</a>) so I was wondering if this approximation was affecting the clusters being generated, especially since we have quite a few landmarks far from the high-density region in the center of Paris.</p>

<h2 id="because-the-earth-isnt-flat-enter-hdbscan">Because the Earth isn’t flat: enter HDBSCAN</h2>

<p>Hence, we need a clustering method that can handle <a href="https://en.wikipedia.org/wiki/Geographical_distance">Geographical distances</a>, meaning lengths of the shortest curve between two points along the surface of the Earth.</p>

<p>A density function such as <a href="http://hdbscan.readthedocs.io/en/latest/index.html">HDBSCAN</a>, which is based on the <a href="https://en.wikipedia.org/wiki/DBSCAN">DBScan</a> algorithm, may be useful for this.</p>

<p>Both HDBSCAN and DBSCAN algorithms are density-based spatial clustering method that group together points that are close to each other based on a distance measurement and a minimum number of points. It also marks as outliers the points that are in low-density regions.</p>

<p>Thankfully, HDBSCAN supports <a href="https://en.wikipedia.org/wiki/Haversine_formula">haversine distance</a> (i.e. longitude/latitude distances) which will properly compute distances between geo-locations. For more on HDBSCAN, check out this <a href="https://towardsdatascience.com/lightning-talk-clustering-with-hdbscan-d47b83d1b03a">blog post</a>.</p>

<p>HDBSCAN isn’t included in your typical Python distribution so you’ll have to pip or conda install it. I did so, and then ran the code below.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">hdbscan</span>

<span class="c1"># Apply HDBSCAN clustering with haversine distance
</span><span class="n">clusterer</span> <span class="o">=</span> <span class="n">hdbscan</span><span class="p">.</span><span class="n">HDBSCAN</span><span class="p">(</span>
    <span class="n">min_cluster_size</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span>
    <span class="n">metric</span><span class="o">=</span><span class="s">'haversine'</span>
<span class="p">)</span>

<span class="c1"># Convert coordinates to radians for haversine distance
</span><span class="n">coordinates_rad</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">radians</span><span class="p">(</span><span class="n">coordinates_array</span><span class="p">)</span>
<span class="n">cluster_labels</span> <span class="o">=</span> <span class="n">clusterer</span><span class="p">.</span><span class="n">fit_predict</span><span class="p">(</span><span class="n">coordinates_rad</span><span class="p">)</span>

<span class="c1"># Add cluster labels to dataframe
</span><span class="n">df</span><span class="p">[</span><span class="s">'HDBSCAN_Cluster'</span><span class="p">]</span> <span class="o">=</span> <span class="n">cluster_labels</span>
</code></pre></div></div>

<p>And ended up with the following scatter plot and dataframe. We see that isolated points were clustered in cluster ‘-1’ which means they were identified as ‘noise’.</p>

<p>Unsurprisingly, we end up with several points being flagged as noise. Since the minimum number of points for a HDBSCAN cluster is 2, isolated locations like the Palais de Versailles were categorised as noise. Sainte-Chapelle de Vincennes, and Musée Rodin suffered a similar fate.</p>

<p>The interesting part however is in the number of clusters that HDBSCAN identified which is 9 — one less than the set vacation days. I guess that for the number of sights/data points that we chose, 10 days sounds like it’ll be okay.</p>

<p>Ultimately, the results from k-means were the ones we used to lay out a schedule as the clusters generated by k-means were similar to the ones generated by HDBSCAN and all data points were included.</p>

<h2 id="conclusion-and-future-improvements">Conclusion and Future Improvements</h2>

<p>The clustering method presented here can be improved of course. One possible improvement is in the addition of a weight feature for the datapoints. For instance, the weights could represent the amount of time needed to fully visit a particular venue (e.g. Le Louvre easily takes one full day to appreciate), and hence this would affect total number of data points in a cluster with highly weighted points — something to investigate in future projects.</p>

<p><strong>Jupyter Notebook for this mini-project can be <a href="https://github.com/hamzaben86/Vacation-Clustering-MiniProject">found here</a>.</strong></p>

<hr />

<p><em>If you found this article helpful, feel free to connect with me on <a href="https://linkedin.com/in/hamzabendemra" target="_blank" rel="noopener">LinkedIn</a> or check out my other articles on <a href="https://medium.com/@hamzabendemra" target="_blank" rel="noopener">Medium</a>.</em></p>]]></content><author><name></name></author><category term="data-science" /><category term="machine-learning" /><category term="machine-learning" /><category term="clustering" /><category term="unsupervised-learning" /><category term="k-means" /><category term="hdbscan" /><category term="geolocation" /><category term="travel" /><category term="python" /><summary type="html"><![CDATA[A practical application of K-Means and HDBSCAN clustering algorithms to optimize travel itinerary planning using geo-location data from Paris landmarks and attractions.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://bendemra.ai/assets/images/posts/paris-clustering.jpg" /><media:content medium="image" url="https://bendemra.ai/assets/images/posts/paris-clustering.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Build Your First Deep Learning Classifier using TensorFlow: Dog Breed Example</title><link href="https://bendemra.ai/data-science/deep-learning/2018/04/26/build-your-first-deep-learning-classifier-using-tensorflow-dog-breed-example.html" rel="alternate" type="text/html" title="Build Your First Deep Learning Classifier using TensorFlow: Dog Breed Example" /><published>2018-04-26T06:00:00+00:00</published><updated>2018-04-26T06:00:00+00:00</updated><id>https://bendemra.ai/data-science/deep-learning/2018/04/26/build-your-first-deep-learning-classifier-using-tensorflow-dog-breed-example</id><content type="html" xml:base="https://bendemra.ai/data-science/deep-learning/2018/04/26/build-your-first-deep-learning-classifier-using-tensorflow-dog-breed-example.html"><![CDATA[<blockquote>
  <p><em>Originally published on <a href="https://medium.com/data-science/build-your-first-deep-learning-classifier-using-tensorflow-dog-breed-example-964ed0689430">Medium</a> on April 26, 2018</em></p>
</blockquote>

<p><img src="https://unsplash.com/photos/iar-afB0QQw/download?force=true&amp;w=800" alt="Neural Network Architecture" />
<em>Convolutional Neural Networks (like the one pictured above) are powerful tools for Image Classification</em></p>

<h2 id="introduction">Introduction</h2>

<p>In this article, I will present several techniques for you to make your first steps towards developing an algorithm that could be used for a classic image classification problem: detecting dog breed from an image.</p>

<p>By the end of this article, we’ll have developed code that will accept any user-supplied image as input and return an estimate of the dog’s breed. Also, if a human is detected, the algorithm will provide an estimate of the dog breed that is most resembling.</p>

<h1 id="1-what-are-convolutional-neural-networks">1. What are Convolutional Neural Networks?</h1>

<p>Convolutional neural networks (also referred to as CNN or ConvNet) are a class of deep neural networks that have seen widespread adoption in a number of computer vision and visual imagery applications.</p>

<p>A famous case of CNN application was detailed in this <a href="https://www.nature.com/articles/nature21056?error=cookies_not_supported&amp;code=c8ab8524-38e7-47c0-af7a-5912873b07b6">research paper</a> by a Stanford research team in which they demonstrated classification of skin lesions using a single CNN. The Neural Network was trained from images using only pixels and disease labels as inputs.</p>

<p>Convolutional Neural Networks consist of multiple layers designed to require relatively little pre-processing compared to other image classification algorithms.</p>

<p>They learn by using filters and applying them to the images. The algorithm takes a small square (or ‘window’) and starts applying it over the image. Each filter allows the CNN to identify certain patterns in the image. The CNN looks for parts of the image where a filter matches the contents of the image.</p>

<p><img src="https://unsplash.com/photos/Q1p7bh3SHj8/download?force=true&amp;w=800" alt="CNN Architecture" />
<em>An example of a CNN Layer Architecture for Image Classification</em></p>

<p>The first few layers of the network may detect simple features like lines, circles, edges. In each layer, the network is able to combine these findings and continually learn more complex concepts as we go deeper and deeper into the layers of the Neural Network.</p>

<h2 id="11-what-kinds-of-layers-are-there">1.1 What kinds of layers are there?</h2>

<p>The overall architecture of a CNN consists of an input layer, hidden layer(s), and an output layer. They are several types of layers, for e.g. Convolutional, Activation, Pooling, Dropout, Dense, and SoftMax layer.</p>

<p><img src="https://unsplash.com/photos/FO7JIlwjOtU/download?force=true&amp;w=800" alt="Neural Network Layers" />
<em>Neural Networks consist of an input layer, hidden layers, and an output layer</em></p>

<p>The Convolutional Layer (or Conv layer) is at the core of what makes a Convolutional Neural Network. The Conv layer consists of a set of filters. Every filter can be considered as a small square (with a fixed width and height) which extends through the full depth of the input volume.</p>

<p>During each pass, the filter ‘convolves’ across the width and height of the input volume. This process results in a 2-dimensional activation map that gives the responses of that filter at every spatial position.</p>

<p>To avoid over-fitting, Pooling layers are used to apply non-linear downsampling on activation maps. In other words, Pooling Layers are aggressive at discarding information but can be useful if used appropriately. A Pooling layer would often follow one or two Conv Layers in CNN architecture.</p>

<p>Dropout Layers are also used to reduce over-fitting, by randomly ignore certain activations functions, while Dense Layers are fully connected layers and often come at the end of the Neural Network.</p>

<h2 id="12-what-are-activation-functions">1.2 What are Activation Functions?</h2>

<p>The output of the layers and of the neural network are processed using an activation function, which is a node that is added to the hidden layers and to the output layer.</p>

<p>You’ll often find that the ReLu activation function is used in hidden layers, while the final layer typically consists of a SoftMax activation function. The idea is that by stacking layers of linear and non-linear functions, we can detect a large range of patterns and accurately predict a label for a given image.</p>

<p>SoftMax is often found in the final layer which acts as basically a normalizer and produces a discrete probability distribution vector, which is great for us as the CNN’s output we want is a probability that an image corresponds to a particular class.</p>

<p>When it comes to model evaluation and performance assessment, a loss function is chosen. In CNNs for image classification, the <a href="https://aboveintelligent.com/deep-learning-basics-the-score-function-cross-entropy-d6cc20c9f972">categorical cross-entropy</a> is often chosen (in a nutshell: it corresponds to -log(error)). There are several methods to minimise the error using Gradient Descent — in this article, we’ll rely on “<a href="http://ruder.io/optimizing-gradient-descent/">rmsprop</a>”, which adaptive learning rate method, as an optimizer with accuracy as a metric.</p>

<h1 id="2-setting-up-the-algorithms-building-blocks">2. Setting up the algorithm’s building blocks</h1>

<p>To build our algorithm, we’ll be using <a href="https://www.tensorflow.org/">TensorFlow</a>, <a href="https://keras.io/">Keras</a> (neural networks API running on top of TensorFlow), and <a href="https://opencv.org/">OpenCV</a> (computer vision library).</p>

<p>Training and testing datasets were also available on-hand when completing this project (see <a href="https://github.com/udacity/dog-project">GitHub repo</a>).</p>

<h2 id="21-detecting-if-image-contains-a-human-face">2.1 Detecting if Image Contains a Human Face</h2>

<p>To detect whether the image supplied is a human face, we’ll use one of OpenCV’s <a href="https://docs.opencv.org/trunk/d7/d8b/tutorial_py_face_detection.html">Face Detection algorithm</a>. Before using any of the face detectors, it is standard procedure to convert the images to grayscale. Below, the <code class="language-plaintext highlighter-rouge">detectMultiScale</code> function executes the classifier stored in <code class="language-plaintext highlighter-rouge">face_cascade</code> and takes the grayscale image as a parameter.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">cv2</span>

<span class="c1"># Load the cascade
</span><span class="n">face_cascade</span> <span class="o">=</span> <span class="n">cv2</span><span class="p">.</span><span class="n">CascadeClassifier</span><span class="p">(</span><span class="s">'haarcascade_frontalface_alt.xml'</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">face_detector</span><span class="p">(</span><span class="n">img_path</span><span class="p">):</span>
    <span class="n">img</span> <span class="o">=</span> <span class="n">cv2</span><span class="p">.</span><span class="n">imread</span><span class="p">(</span><span class="n">img_path</span><span class="p">)</span>
    <span class="n">gray</span> <span class="o">=</span> <span class="n">cv2</span><span class="p">.</span><span class="n">cvtColor</span><span class="p">(</span><span class="n">img</span><span class="p">,</span> <span class="n">cv2</span><span class="p">.</span><span class="n">COLOR_BGR2GRAY</span><span class="p">)</span>
    <span class="n">faces</span> <span class="o">=</span> <span class="n">face_cascade</span><span class="p">.</span><span class="n">detectMultiScale</span><span class="p">(</span><span class="n">gray</span><span class="p">)</span>
    <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="n">faces</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span>
</code></pre></div></div>

<h2 id="22-detecting-if-image-contains-a-dog">2.2 Detecting if Image Contains a Dog</h2>

<p>To detect whether the image supplied contains a face of a dog, we’ll use a pre-trained <a href="http://ethereon.github.io/netscope/#/gist/db945b393d40bfa26006">ResNet-50</a> model using the <a href="https://en.wikipedia.org/wiki/ImageNet">ImageNet</a> dataset which can classify an object from one of <a href="https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a">1000 categories</a>. Given an image, this pre-trained <a href="http://ethereon.github.io/netscope/#/gist/db945b393d40bfa26006">ResNet-50 model</a> returns a prediction for the object that is contained in the image.</p>

<p>When using <a href="https://www.tensorflow.org/">TensorFlow</a> as backend, <a href="https://keras.io/">Keras</a> CNNs require a 4D array as input. The <code class="language-plaintext highlighter-rouge">path_to_tensor</code> function below takes a string-valued file path to a color image as input, resizes it to a square image that is 224x224 pixels, and returns a 4D array (referred to as a ‘tensor’) suitable for supplying to a Keras CNN.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">keras.preprocessing</span> <span class="kn">import</span> <span class="n">image</span>
<span class="kn">from</span> <span class="nn">keras.applications.resnet50</span> <span class="kn">import</span> <span class="n">ResNet50</span><span class="p">,</span> <span class="n">preprocess_input</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>

<span class="k">def</span> <span class="nf">path_to_tensor</span><span class="p">(</span><span class="n">img_path</span><span class="p">):</span>
    <span class="c1"># loads RGB image as PIL.Image.Image type
</span>    <span class="n">img</span> <span class="o">=</span> <span class="n">image</span><span class="p">.</span><span class="n">load_img</span><span class="p">(</span><span class="n">img_path</span><span class="p">,</span> <span class="n">target_size</span><span class="o">=</span><span class="p">(</span><span class="mi">224</span><span class="p">,</span> <span class="mi">224</span><span class="p">))</span>
    <span class="c1"># convert PIL.Image.Image type to 3D tensor with shape (224, 224, 3)
</span>    <span class="n">x</span> <span class="o">=</span> <span class="n">image</span><span class="p">.</span><span class="n">img_to_array</span><span class="p">(</span><span class="n">img</span><span class="p">)</span>
    <span class="c1"># convert 3D tensor to 4D tensor with shape (1, 224, 224, 3) and return 4D tensor
</span>    <span class="k">return</span> <span class="n">np</span><span class="p">.</span><span class="n">expand_dims</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">ResNet50_predict_labels</span><span class="p">(</span><span class="n">img_path</span><span class="p">):</span>
    <span class="c1"># returns prediction vector for image located at img_path
</span>    <span class="n">img</span> <span class="o">=</span> <span class="n">preprocess_input</span><span class="p">(</span><span class="n">path_to_tensor</span><span class="p">(</span><span class="n">img_path</span><span class="p">))</span>
    <span class="k">return</span> <span class="n">np</span><span class="p">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">ResNet50_model</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">img</span><span class="p">))</span>
</code></pre></div></div>

<p>Also, all pre-trained models have the additional normalization step that the mean pixel must be subtracted from every pixel in each image. This is implemented in imported function <code class="language-plaintext highlighter-rouge">preprocess_input</code>.</p>

<p>As shown in the code above, for the final prediction we obtain an integer corresponding to the model’s predicted object class by taking the <a href="https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.argmax.html">argmax</a> of the predicted probability vector, which we can identify with an object category through the use of the ImageNet labels <a href="https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a">dictionary</a>.</p>

<h1 id="3-build-your-cnn-classifier-using-transfer-learning">3. Build your CNN Classifier using Transfer Learning</h1>

<p>Now that we have functions for detecting humans and dogs in images, we need a way to predict breed from images. In this section, we will create a CNN that classifies dog breeds.</p>

<p>To reduce training time without sacrificing accuracy, we’ll be training a CNN using <a href="https://towardsdatascience.com/transfer-learning-leveraging-insights-from-large-data-sets-d5435071ec5a">Transfer Learning</a> — which is a method that allows us to use Networks that have been pre-trained on a large dataset. By keeping the early layers and only training newly added layers, we are able to tap into the knowledge gained by the pre-trained algorithm and use it for our application.</p>

<p><a href="https://keras.io/applications/">Keras</a> includes several pre-trained deep learning models that can be used for prediction, feature extraction, and fine-tuning.</p>

<h2 id="31-model-architecture">3.1 Model Architecture</h2>

<p>As previously mentioned, the <a href="https://github.com/KaimingHe/deep-residual-networks">ResNet-50 model</a> output is going to be our input layer — called the bottleneck features. In the code block below, we extract the bottleneck features corresponding to the train, test, and validation sets by running the following.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">keras.applications.resnet50</span> <span class="kn">import</span> <span class="n">ResNet50</span>

<span class="c1"># define ResNet50 model
</span><span class="n">ResNet50_model</span> <span class="o">=</span> <span class="n">ResNet50</span><span class="p">(</span><span class="n">weights</span><span class="o">=</span><span class="s">'imagenet'</span><span class="p">,</span> <span class="n">include_top</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">extract_Resnet50</span><span class="p">(</span><span class="n">tensor</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">ResNet50_model</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">preprocess_input</span><span class="p">(</span><span class="n">tensor</span><span class="p">))</span>
</code></pre></div></div>

<p>We’ll set up our model architecture such that the last convolutional output of ResNet-50 is fed as input to our model. We only add a <a href="https://keras.io/layers/pooling/">Global Average Pooling</a> layer and a <a href="https://keras.io/layers/core/">Fully Connected</a> layer, where the latter contains one node for each dog category and has a <a href="https://keras.io/activations/#softmax">Softmax</a> activation function.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">keras.layers</span> <span class="kn">import</span> <span class="n">GlobalAveragePooling2D</span><span class="p">,</span> <span class="n">Dense</span>
<span class="kn">from</span> <span class="nn">keras.models</span> <span class="kn">import</span> <span class="n">Sequential</span>

<span class="n">Resnet50_model</span> <span class="o">=</span> <span class="n">Sequential</span><span class="p">()</span>
<span class="n">Resnet50_model</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">GlobalAveragePooling2D</span><span class="p">(</span><span class="n">input_shape</span><span class="o">=</span><span class="p">(</span><span class="mi">7</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">2048</span><span class="p">)))</span>
<span class="n">Resnet50_model</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">Dense</span><span class="p">(</span><span class="mi">133</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'softmax'</span><span class="p">))</span>

<span class="n">Resnet50_model</span><span class="p">.</span><span class="n">summary</span><span class="p">()</span>
</code></pre></div></div>

<p>As we can see in the above code’s output, we end up with a Neural Network with 272,517 parameters!</p>

<h2 id="32-compile--test-the-model">3.2 Compile &amp; Test the Model</h2>

<p>Now, we can use the CNN to test how well it identifies breed within our test dataset of dog images. To fine-tune the model, we go through 20 iterations (or ‘<a href="https://towardsdatascience.com/epoch-vs-iterations-vs-batch-size-4dfb9c7ce9c9">epochs</a>’) in which the model’s hyper-parameters are fine-tuned to reduce the loss function (<a href="https://rdipietro.github.io/friendly-intro-to-cross-entropy-loss/">categorical cross-entropy</a>) which is optimised using RMS Prop.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Resnet50_model</span><span class="p">.</span><span class="nb">compile</span><span class="p">(</span><span class="n">loss</span><span class="o">=</span><span class="s">'categorical_crossentropy'</span><span class="p">,</span> <span class="n">optimizer</span><span class="o">=</span><span class="s">'rmsprop'</span><span class="p">,</span> <span class="n">metrics</span><span class="o">=</span><span class="p">[</span><span class="s">'accuracy'</span><span class="p">])</span>

<span class="n">Resnet50_model</span><span class="p">.</span><span class="n">fit</span><span class="p">(</span><span class="n">train_Resnet50</span><span class="p">,</span> <span class="n">train_targets</span><span class="p">,</span> 
          <span class="n">validation_data</span><span class="o">=</span><span class="p">(</span><span class="n">valid_Resnet50</span><span class="p">,</span> <span class="n">valid_targets</span><span class="p">),</span>
          <span class="n">epochs</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span> <span class="n">batch_size</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span> <span class="n">verbose</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>

<span class="c1"># get index of predicted dog breed for each image in test set
</span><span class="n">Resnet50_predictions</span> <span class="o">=</span> <span class="p">[</span><span class="n">np</span><span class="p">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">Resnet50_model</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">expand_dims</span><span class="p">(</span><span class="n">tensor</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">)))</span> <span class="k">for</span> <span class="n">tensor</span> <span class="ow">in</span> <span class="n">test_Resnet50</span><span class="p">]</span>

<span class="c1"># report test accuracy
</span><span class="n">test_accuracy</span> <span class="o">=</span> <span class="mi">100</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="nb">sum</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">Resnet50_predictions</span><span class="p">)</span><span class="o">==</span><span class="n">np</span><span class="p">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">test_targets</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">))</span><span class="o">/</span><span class="nb">len</span><span class="p">(</span><span class="n">Resnet50_predictions</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Test accuracy: %.4f%%'</span> <span class="o">%</span> <span class="n">test_accuracy</span><span class="p">)</span>
</code></pre></div></div>

<p><strong>Test accuracy: 80.0239%</strong></p>

<p>Provided with a testing set, the algorithm scored a testing accuracy of 80%. Not bad at all!</p>

<h2 id="33-predict-dog-breed-with-the-model">3.3 Predict Dog Breed with the Model</h2>

<p>Now that we have the algorithm, let’s write a function that takes an image path as input and returns the dog breed that is predicted by our model.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">Resnet50_predict_breed</span><span class="p">(</span><span class="n">img_path</span><span class="p">):</span>
    <span class="c1"># extract bottleneck features
</span>    <span class="n">bottleneck_feature</span> <span class="o">=</span> <span class="n">extract_Resnet50</span><span class="p">(</span><span class="n">path_to_tensor</span><span class="p">(</span><span class="n">img_path</span><span class="p">))</span>
    <span class="c1"># obtain predicted vector
</span>    <span class="n">predicted_vector</span> <span class="o">=</span> <span class="n">Resnet50_model</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">bottleneck_feature</span><span class="p">)</span>
    <span class="c1"># return dog breed that is predicted by the model
</span>    <span class="k">return</span> <span class="n">dog_names</span><span class="p">[</span><span class="n">np</span><span class="p">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">predicted_vector</span><span class="p">)]</span>
</code></pre></div></div>

<h1 id="4-testing-our-cnn-classifier">4. Testing our CNN Classifier</h1>

<p>Now, we can write a function that takes accepts a file path to an image and first determines whether the image contains a human, dog, or neither.</p>

<p>If a dog is detected in the image, return the predicted breed. If a human is detected in the image, return the resembling dog breed. If neither is detected in the image, provide output that indicates an error.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">run_app</span><span class="p">(</span><span class="n">img_path</span><span class="p">):</span>
    <span class="c1">## handle cases for a human face, dog, and neither
</span>    <span class="k">if</span> <span class="n">dog_detector</span><span class="p">(</span><span class="n">img_path</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">Resnet50_predict_breed</span><span class="p">(</span><span class="n">img_path</span><span class="p">)</span>
    <span class="k">elif</span> <span class="n">face_detector</span><span class="p">(</span><span class="n">img_path</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">Resnet50_predict_breed</span><span class="p">(</span><span class="n">img_path</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">return</span> <span class="s">"Error: Neither human nor dog detected in image."</span>
</code></pre></div></div>

<p>We are ready to take the algorithm for a spin! Let’s test the algorithm on a few sample images:</p>

<p><img src="https://unsplash.com/photos/av3cmVU_bmM/download?force=true&amp;w=800" alt="Dog classification results" />
<em>Testing our deep learning classifier on real images</em></p>

<p>These predictions look accurate to me!</p>

<p>On a final note, I noted that that the algorithm is prone to errors unless it’s a clear facing shot with minimal noise on the image. Hence, we need to make the algorithm more robust to noise. Also, a method we can use to improve our classifier is <a href="https://medium.com/nanonets/how-to-use-deep-learning-when-you-have-limited-data-part-2-data-augmentation-c26971dc8ced">image augmentation</a> which allows you to “augment” your data by providing variations of the images supplied in the training set.</p>

<hr />

<p><em>If you found this article helpful, feel free to connect with me on <a href="https://linkedin.com/in/hamzabendemra" target="_blank" rel="noopener">LinkedIn</a> or check out my other articles on <a href="https://medium.com/@hamzabendemra" target="_blank" rel="noopener">Medium</a>.</em></p>]]></content><author><name></name></author><category term="data-science" /><category term="deep-learning" /><category term="deep-learning" /><category term="tensorflow" /><category term="keras" /><category term="cnn" /><category term="neural-networks" /><category term="machine-learning" /><category term="computer-vision" /><category term="transfer-learning" /><summary type="html"><![CDATA[A comprehensive tutorial on building your first deep learning classifier using TensorFlow and Keras, featuring Convolutional Neural Networks, transfer learning, and practical dog breed classification with 80% accuracy.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://bendemra.ai/assets/images/posts/deep-learning-classifier.jpg" /><media:content medium="image" url="https://bendemra.ai/assets/images/posts/deep-learning-classifier.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Setting up Databases with PostgreSQL, PSequel, and Python</title><link href="https://bendemra.ai/data-science/data-engineering/2018/04/23/setting-up-databases-with-postgresql-psequel-and-python.html" rel="alternate" type="text/html" title="Setting up Databases with PostgreSQL, PSequel, and Python" /><published>2018-04-23T06:00:00+00:00</published><updated>2018-04-23T06:00:00+00:00</updated><id>https://bendemra.ai/data-science/data-engineering/2018/04/23/setting-up-databases-with-postgresql-psequel-and-python</id><content type="html" xml:base="https://bendemra.ai/data-science/data-engineering/2018/04/23/setting-up-databases-with-postgresql-psequel-and-python.html"><![CDATA[<blockquote>
  <p><em>Originally published on <a href="http://medium.com/data-science/leveraging-python-with-large-databases-pandas-postgresql-5073825167e0">Medium</a> on April 23, 2018</em></p>
</blockquote>

<p><img src="https://unsplash.com/photos/JKUTrJ4vK00/download?force=true&amp;w=800" alt="Database streaming and processing" />
<em>Working with large databases requires proper tools and techniques</em></p>

<p>As the demand for Data Scientists <a href="https://edgylabs.com/data-scientist-is-americas-best-career-for-the-third-year-running">continues to increase</a>, and is being dubbed the “sexiest job of the 21st century” by various outlets (including <a href="https://hbr.org/2012/10/data-scientist-the-sexiest-job-of-the-21st-century">Harvard Business Review</a>), questions have been asked of what skills should aspiring data scientists master on their way to their first data analyst job.</p>

<p>There is now a plethora of online courses to gain the skills needed for a data scientist to be good at their job (excellent reviews of online resources <a href="https://medium.com/personal-growth/16-top-rated-data-science-courses-e5e161b937c3">here</a> and <a href="https://medium.freecodecamp.org/a-path-for-you-to-learn-analytics-and-data-skills-bd48ccde7325">here</a>). However, as I reviewed the various courses myself, I noticed that a lot of focus is put on exciting and flashy topics like Machine Learning and Deep Learning without covering the basics of what is needed to gather and store datasets needed for such analysis.</p>

<h2 id="big-data-science">(Big) Data Science</h2>

<p>Before we go into PostgreSQL, I suspect many of you have the same question: why should I care about SQL?</p>

<p>Although database management may seem like a boring topic for aspiring data scientists — implementing a dog breed classifier is very rewarding I know! — it is a necessary skill once you join the industry and the data supports this: SQL remains the most common and <a href="https://www.kdnuggets.com/2016/02/data-science-skills-2016.html">in-demand skill</a> listed in LinkedIn job postings for data science jobs.</p>

<p><img src="https://unsplash.com/photos/wX2L8L-fGeA/download?force=true&amp;w=800" alt="SQL and Big Data" />
<em>SQL is a necessary skill in many data science applications with large datasets</em></p>

<p><a href="https://pandas.pydata.org/">Pandas</a> can perform the most common SQL operations well but is not suitable for large databases — its main limit comes to the amount of data one can fit in memory. Hence, if a data scientist is working with large databases, SQL is used to transform the data into something manageable for pandas before loading it in memory.</p>

<p>Furthermore, SQL is much more than just a method to have flat files dropped into a table. The power of SQL comes in the way that it allows users to have a set of tables that “relate” to one another, this is often represented in an “Entity Relationship Diagram” or ERD.</p>

<p>Many data scientists use both simultaneously — they use SQL queries to join, slice and load data into memory; then they do the bulk of the data analysis in Python using <a href="https://pandas.pydata.org/">pandas</a> library functions.</p>

<p><img src="https://unsplash.com/photos/xbEVM6oJ1Fs/download?force=true&amp;w=800" alt="Entity Relationship Diagram" />
<em>Example of an ERD showing relationships between database tables</em></p>

<p>This is particularly important when dealing with the large datasets found in Big Data applications. Such applications would have tens of TBs in databases with several billion rows.</p>

<p>Data Scientists often start with SQL queries that would extract 1% of data needed to a csv file, before moving to Python Pandas for data analysis.</p>

<h2 id="enter-postgresql">Enter PostgreSQL</h2>

<p>There is a way to learn SQL without leaving the much loved Python environment in which so much Machine Learning and Deep Learning techniques are taught and used: PostgreSQL.</p>

<p><a href="https://www.postgresql.org/">PostgreSQL</a> allows you to leverage the amazing <a href="https://pandas.pydata.org/">Pandas library</a> for data wrangling when dealing with large datasets that are not stored in flat files but rather in databases.</p>

<p>PostgreSQL can be installed in Windows, Mac, and Linux environments (see <a href="https://www.tutorialspoint.com/postgresql/postgresql_environment.htm">install details here</a>). If you have a Mac, I’d highly recommend installing the <a href="http://postgresapp.com/">Postgres.App</a> SQL environment. For Windows, check out <a href="https://www.openscg.com/bigsql/postgresql/installers.jsp/">BigSQL</a>.</p>

<p>PostgreSQL uses a client/server model. This involves two running processes:</p>

<p>• <strong>Server process</strong>: manages database files, accepts connections to the database from client applications, and performs database actions on behalf of the clients.
• <strong>User Client App</strong>: often involves SQL command entries, a friendly graphical interface, and some database maintenance tool.</p>

<p>In real-case scenarios, the client and the server will often be on different hosts and they would communicate over a TCP/IP network connection.</p>

<h2 id="installing-postgresapp-and-psequel">Installing Postgres.App and PSequel</h2>

<p>I’ll be focusing on Postgres.App for Mac OS in the rest of the tutorial. After installing <a href="https://postgresapp.com/">PostgresApp</a>, you can setup your first database by following the instructions below:</p>

<p>• Click “Initialize” to create a new server
• An optional step is to configure a <code class="language-plaintext highlighter-rouge">$PATH</code> to be able to use the command line tools delivered with Postgres.app by executing the following command in Terminal and then close &amp; reopen the window:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo mkdir</span> <span class="nt">-p</span> /etc/paths.d <span class="o">&amp;&amp;</span> <span class="nb">echo</span> /Applications/Postgres.app/Contents/Versions/latest/bin | <span class="nb">sudo tee</span> /etc/paths.d/postgresapp
</code></pre></div></div>

<p>You now have a PostgreSQL server running on your Mac with default settings:
<code class="language-plaintext highlighter-rouge">Host: localhost, Port: 5432, Connection URL: postgresql://localhost</code></p>

<p>The PostgreSQL GUI client we’ll use in this tutorial is <a href="http://www.psequel.com/">PSequel</a>. It has a minimalist and easy to use interface that I really enjoy to easily perform PostgreSQL tasks.</p>

<p><img src="https://unsplash.com/photos/mcSDtbWXUZU/download?force=true&amp;w=800" alt="PSequel Interface" />
<em>Graphical SQL Client of choice: PSequel provides a clean, intuitive interface</em></p>

<h2 id="creating-your-first-database">Creating Your First Database</h2>

<p>Once Postgres.App and PSequel installed, you are now ready to set up your first database! First, start by opening Postgres.App and you’ll see a little elephant icon appear in the top menu.</p>

<p>You’ll also notice a button that allows you to “Open psql”. This will open a command line that will allow you to enter commands. This is mostly used to create databases, which we will create using the following command:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">CREATE</span> <span class="k">DATABASE</span> <span class="n">sample_db</span><span class="p">;</span>
</code></pre></div></div>

<p>Then, we connect to the database we just created using PSequel. We’ll open PSequel and enter the database name, in our case: <code class="language-plaintext highlighter-rouge">sample_db</code>. Click on “Connect” to connect to the database.</p>

<h2 id="creating-and-populating-your-first-table">Creating and Populating Your First Table</h2>

<p>Let’s create a table (consisting of rows and columns) in PSequel. We define the table’s name, and the name and type of each column.</p>

<p>The available datatypes in PostgreSQL for the columns (i.e. variables), can be found on the PostgreSQL <a href="https://www.postgresql.org/docs/10/static/datatype.html">Datatypes Documentation</a>.</p>

<p>In this tutorial, we’ll create a simple table with world countries. The first column will provide each country an ‘id’ integer, and the second column will provide the country’s name using variable length character string (with 255 characters max).</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">CREATE</span> <span class="k">TABLE</span> <span class="n">country_list</span> <span class="p">(</span>
    <span class="n">id</span> <span class="nb">INTEGER</span><span class="p">,</span>
    <span class="n">name</span> <span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Once ready, click “Run Query”. The table will then be created in the database. Don’t forget to click the “Refresh” icon (bottom right) to see the table listed.</p>

<p>We are now ready to populate our columns with data. There are many different ways to populate a table in a database. To enter data manually, the <code class="language-plaintext highlighter-rouge">INSERT</code> will come in handy. For instance, to enter the country Morocco with id number 1, and Australia with id number 2, the SQL command is:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">INSERT</span> <span class="k">INTO</span> <span class="n">country_list</span> <span class="p">(</span><span class="n">id</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span> <span class="k">VALUES</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s1">'Morocco'</span><span class="p">);</span>
<span class="k">INSERT</span> <span class="k">INTO</span> <span class="n">country_list</span> <span class="p">(</span><span class="n">id</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span> <span class="k">VALUES</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="s1">'Australia'</span><span class="p">);</span>
</code></pre></div></div>

<p>In practice, populating the tables in the database manually is not feasible. It is likely that the data of interest is stored in CSV files. To import a CSV file into the <code class="language-plaintext highlighter-rouge">country_list_csv</code> table, you use <code class="language-plaintext highlighter-rouge">COPY</code> statement as follows:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">COPY</span> <span class="n">country_list_csv</span><span class="p">(</span><span class="n">id</span><span class="p">,</span><span class="n">name</span><span class="p">)</span>
<span class="k">FROM</span> <span class="s1">'C:</span><span class="se">\{</span><span class="s1">path}</span><span class="se">\{</span><span class="s1">file_name}.csv'</span> 
<span class="k">DELIMITER</span> <span class="s1">','</span> <span class="n">CSV</span> <span class="n">HEADER</span><span class="p">;</span>
</code></pre></div></div>

<p>As you can see in the commands above, the table with column names is specified after the <code class="language-plaintext highlighter-rouge">COPY</code> command. The columns must be ordered in the same fashion as in the CSV file. The CSV file path is specified after the <code class="language-plaintext highlighter-rouge">FROM</code> keyword. The CSV <code class="language-plaintext highlighter-rouge">DELIMITER</code> must also be specified.</p>

<p>If the CSV file contains a header line with column names, it is indicated with the <code class="language-plaintext highlighter-rouge">HEADER</code> keyword so that PostgreSQL ignores the first line when importing the data from the CSV file.</p>

<h2 id="common-sql-commands">Common SQL Commands</h2>

<p>The key to SQL is understanding statements. A few statements include:</p>

<ol>
  <li><strong>CREATE TABLE</strong> is a statement that creates a new table in a database.</li>
  <li><strong>DROP TABLE</strong> is a statement that removes a table in a database.</li>
  <li><strong>SELECT</strong> allows you to read data and display it.</li>
</ol>

<p>SELECT is where you tell the query what columns you want back. FROM is where you tell the query what table you are querying from. Notice the columns need to exist in this table. For example, let’s say we have a table of orders with several columns but we are only interested in a subset of three:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="n">id</span><span class="p">,</span> <span class="n">account_id</span><span class="p">,</span> <span class="n">occurred_at</span>
<span class="k">FROM</span> <span class="n">orders</span><span class="p">;</span>
</code></pre></div></div>

<p>Also, the <strong>LIMIT</strong> statement is useful when you want to see just the first few rows of a table. This can be much faster for loading than if we load the entire dataset. The <strong>ORDER BY</strong> statement allows us to order our table by any row. We can use these two commands together to a table of ‘orders’ in a database as:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="n">id</span><span class="p">,</span> <span class="n">account_id</span><span class="p">,</span> <span class="n">total_amt_usd</span>
<span class="k">FROM</span> <span class="n">orders</span>
<span class="k">ORDER</span> <span class="k">BY</span> <span class="n">total_amt_usd</span> <span class="k">DESC</span>
<span class="k">LIMIT</span> <span class="mi">5</span><span class="p">;</span>
</code></pre></div></div>

<h2 id="explore-other-sql-commands">Explore Other SQL Commands</h2>

<p>Now that you know how to setup a database, create a table and populate in PostgreSQL, you can explore the other common SQL commands as explained in the following tutorials:</p>

<p>• <a href="https://towardsdatascience.com/how-to-ace-data-science-interviews-sql-b71de212e433">SQL Basics for Data Science</a>
• <a href="https://www.khanacademy.org/computing/computer-programming/sql/sql-basics/p/creating-a-table-and-inserting-data">Khan Academy: Intro to SQL</a>
• <a href="https://towardsdatascience.com/sql-in-a-nutshell-part-1-basic-real-world-scenarios-33a25ba8d220">SQL in a Nutshell</a>
• <a href="https://www.codecademy.com/articles/sql-commands">Cheat Sheet SQL Commands</a></p>

<h2 id="accessing-postgresql-database-in-python">Accessing PostgreSQL Database in Python</h2>

<p>Once your PostgreSQL database and tables are setup, you can then move to Python to perform any Data Analysis or Wrangling required.</p>

<p>PostgreSQL can be integrated with Python using <a href="http://initd.org/psycopg/docs/">psycopg2 module</a>. It is a popular PostgreSQL database adapter for Python. It is shipped along with default libraries in Python version 2.5.x onwards.</p>

<p>Connecting to an existing PostgreSQL database can be achieved with:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">psycopg2</span>

<span class="n">conn</span> <span class="o">=</span> <span class="n">psycopg2</span><span class="p">.</span><span class="n">connect</span><span class="p">(</span>
    <span class="n">database</span><span class="o">=</span><span class="s">"sample_db"</span><span class="p">,</span> 
    <span class="n">user</span><span class="o">=</span><span class="s">"postgres"</span><span class="p">,</span> 
    <span class="n">password</span><span class="o">=</span><span class="s">"pass123"</span><span class="p">,</span> 
    <span class="n">host</span><span class="o">=</span><span class="s">"127.0.0.1"</span><span class="p">,</span> 
    <span class="n">port</span><span class="o">=</span><span class="s">"5432"</span>
<span class="p">)</span>
</code></pre></div></div>

<p>Going back to our country_list table example, inserting records into the table in sample_db can be accomplished in Python with the following commands:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">cur</span> <span class="o">=</span> <span class="n">conn</span><span class="p">.</span><span class="n">cursor</span><span class="p">()</span>
<span class="n">cur</span><span class="p">.</span><span class="n">execute</span><span class="p">(</span><span class="s">"INSERT INTO country_list (id, name) VALUES (1, 'Morocco')"</span><span class="p">)</span>
<span class="n">cur</span><span class="p">.</span><span class="n">execute</span><span class="p">(</span><span class="s">"INSERT INTO country_list (id, name) VALUES (2, 'Australia')"</span><span class="p">)</span>
<span class="n">conn</span><span class="p">.</span><span class="n">commit</span><span class="p">()</span>
<span class="n">conn</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
</code></pre></div></div>

<p>Other commands for creating, populating and querying tables can be found on various tutorials on <a href="https://www.tutorialspoint.com/postgresql/postgresql_python.htm">Tutorial Points</a> and <a href="http://www.postgresqltutorial.com/postgresql-python/">PostgreSQL Tutorial</a>.</p>

<h2 id="conclusion">Conclusion</h2>

<p>You now have a working PostgreSQL database server ready for you to populate and play with. It’s powerful, flexible, free and is used by numerous applications.</p>

<p>The combination of PostgreSQL’s robustness and Python’s analytical capabilities provides data scientists with a powerful toolkit for handling large datasets that don’t fit comfortably in memory. By mastering these fundamental database skills alongside your machine learning knowledge, you’ll be well-equipped to handle real-world data science challenges.</p>

<hr />

<p><em>If you found this article helpful, feel free to connect with me on <a href="https://linkedin.com/in/hamzabendemra" target="_blank" rel="noopener">LinkedIn</a> or check out my other articles on <a href="https://medium.com/@hamzabendemra" target="_blank" rel="noopener">Medium</a>.</em></p>]]></content><author><name></name></author><category term="data-science" /><category term="data-engineering" /><category term="sql" /><category term="postgresql" /><category term="database" /><category term="python" /><category term="pandas" /><category term="big-data" /><category term="data-engineering" /><category term="psycopg2" /><summary type="html"><![CDATA[A comprehensive guide to setting up and working with PostgreSQL databases for data science, covering installation, basic SQL operations, and Python integration using psycopg2 for handling large datasets.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://bendemra.ai/assets/images/posts/postgresql-python.jpg" /><media:content medium="image" url="https://bendemra.ai/assets/images/posts/postgresql-python.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Using R to Visualise Data on Aviation Tragedies in the US since 1948</title><link href="https://bendemra.ai/data-science/data-analysis/2018/02/16/using-r-to-visualise-data-on-aviation-tragedies-in-the-us-since-1948.html" rel="alternate" type="text/html" title="Using R to Visualise Data on Aviation Tragedies in the US since 1948" /><published>2018-02-16T06:00:00+00:00</published><updated>2018-02-16T06:00:00+00:00</updated><id>https://bendemra.ai/data-science/data-analysis/2018/02/16/using-r-to-visualise-data-on-aviation-tragedies-in-the-us-since-1948</id><content type="html" xml:base="https://bendemra.ai/data-science/data-analysis/2018/02/16/using-r-to-visualise-data-on-aviation-tragedies-in-the-us-since-1948.html"><![CDATA[<blockquote>
  <p><em>Originally published on <a href="https://medium.com/data-science/data-visualisations-of-aviation-tragedies-in-the-us-since-1948-4f1d7371b799">Medium</a> on February 16, 2018</em></p>
</blockquote>

<p><img src="https://unsplash.com/photos/6ArTTluciuA/download?force=true&amp;w=800" alt="Aviation accident investigation" />
<em>NTSB investigators looking at aviation accident scenes help us understand safety patterns</em></p>

<p>In this post, I look at a dataset sourced from the <a href="https://www.ntsb.gov/_layouts/ntsb.aviation/index.aspx">NTSB Aviation Accident Database</a> which contains information about civil aviation accidents. A dataset is available on <a href="https://www.kaggle.com/khsamaha/aviation-accident-database-synopses">Kaggle</a> also.</p>

<p>This <a href="https://towardsdatascience.com/tagged/exploratory-data-analysis">Exploratory Data Analysis</a> (<a href="https://en.wikipedia.org/wiki/Exploratory_data_analysis">EDA</a>) aims to perform an initial exploration of the data and get an initial look at relationships between the various variables present in the dataset.</p>

<p>My aim is to also show how a simple understanding of <a href="https://towardsdatascience.com/tagged/data-analysis">Data Analysis</a> and <a href="https://towardsdatascience.com/tagged/data-wrangling">Wrangling</a> in <a href="https://towardsdatascience.com/tagged/R">R</a> coupled with domain knowledge can provide a better understanding of relationships between variables in a dataset. The R Markdown file can found in this <a href="https://github.com/hamzaben86/Exploratory-Data-Analysis-Projects/tree/master/NSTB-Aviation-Accidents-EDA-R">GitHub repo</a>.</p>

<h1 id="introduction">Introduction</h1>

<p>First, a quick intro of the dataset I’ll be exploring. The dataset features 81,013 observations of 31 variables which are related to aviation accidents recorded.</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Dataset dimensions</span><span class="w">
</span><span class="nf">dim</span><span class="p">(</span><span class="n">aviation_data</span><span class="p">)</span><span class="w">
</span><span class="c1">## [1] 81013    31</span><span class="w">
</span></code></pre></div></div>

<p>Variables provide information on a variety of topics including date and location of observations, model and type of aircraft, information on the sustained injuries to passengers and to the aircraft, and the reported weather conditions at the time.</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Variable names in the dataset</span><span class="w">
</span><span class="nf">names</span><span class="p">(</span><span class="n">aviation_data</span><span class="p">)</span><span class="w">
</span><span class="c1">## [1] "Event.Id"               "Investigation.Type"    </span><span class="w">
</span><span class="c1">## [3] "Accident.Number"        "Event.Date"            </span><span class="w">
</span><span class="c1">## [5] "Location"               "Country"               </span><span class="w">
</span><span class="c1">## [7] "Latitude"               "Longitude"             </span><span class="w">
</span><span class="c1">## [9] "Airport.Code"           "Airport.Name"          </span><span class="w">
</span><span class="c1">## [11] "Injury.Severity"        "Aircraft.Damage"       </span><span class="w">
</span><span class="c1">## [13] "Aircraft.Category"      "Registration.Number"   </span><span class="w">
</span><span class="c1">## [15] "Make"                   "Model"                 </span><span class="w">
</span><span class="c1">## [17] "Amateur.Built"          "Number.of.Engines"     </span><span class="w">
</span><span class="c1">## [19] "Engine.Type"            "FAR.Description"       </span><span class="w">
</span><span class="c1">## [21] "Schedule"               "Purpose.of.Flight"     </span><span class="w">
</span><span class="c1">## [23] "Air.Carrier"            "Total.Fatal.Injuries"  </span><span class="w">
</span><span class="c1">## [25] "Total.Serious.Injuries" "Total.Minor.Injuries"  </span><span class="w">
</span><span class="c1">## [27] "Total.Uninjured"        "Weather.Condition"     </span><span class="w">
</span><span class="c1">## [29] "Broad.Phase.of.Flight"  "Report.Status"         </span><span class="w">
</span><span class="c1">## [31] "Publication.Date"</span><span class="w">
</span></code></pre></div></div>

<h1 id="data-wrangling">Data Wrangling</h1>

<p>Since this an NTSB database from the United States, the majority of accidents (over 94%) in this database are observations in the US. Hence, I will be focusing on the accidents that took place in the US in this analysis. After removing international observations the new dataframe now features 76,188 observations.</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Filter for US accidents only</span><span class="w">
</span><span class="n">us_aviation_data</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">aviation_data</span><span class="p">[</span><span class="n">aviation_data</span><span class="o">$</span><span class="n">Country</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"United States"</span><span class="p">,</span><span class="w"> </span><span class="p">]</span><span class="w">
</span><span class="nf">dim</span><span class="p">(</span><span class="n">us_aviation_data</span><span class="p">)</span><span class="w">
</span><span class="c1">## [1] 76188    31</span><span class="w">
</span></code></pre></div></div>

<p>Some data wrangling was necessary of course (details of which can be found in the R Markdown file in the <a href="https://github.com/hamzaben86/NSTB-Aviation-Accidents-EDA-R">GitHub repo</a>). For instance, the listed location names (city, state) was separated into two variables: one for the city and one for the state, for each observation.</p>

<p>The variable related to the observation’s event date was broken down into the observation’s event date by day, month, and year to investigate if there are any correlations between number of accidents and particular periods within a year.</p>

<p>Also, a better way of displaying data related to total fatalities for a given observation was to group number of fatalities in buckets (or bands). This will give us a better representation of the distribution of fatalities across the observations in the dataset.</p>

<h1 id="univariate-plots-section">Univariate Plots Section</h1>

<p>In this section, I will create univariate plots for variables of interest.</p>

<h2 id="accidents-by-year-month-and-weekday">Accidents by Year, Month, and Weekday</h2>

<p>Let’s plots frequency histograms for the year, month, and weekday of accidents in the dataset. The majority of the observations in the dataframe are from after the early 1980s onwards. So let’s generate a plot from 1980 to 2017.</p>

<p><img src="https://unsplash.com/photos/JKUTrJ4vK00/download?force=true&amp;w=800" alt="Accidents by year" />
<em>Aviation accidents by year show an overall declining trend</em></p>

<p>The number of accidents has overall decreased by approx. 47% between 1982 and 2017 from approx. 3400 observations to approx. 1600 observations.</p>

<p>Next, let’s look at observations distribution by months of the year.</p>

<p>The highest number of accidents in the dataset for a given year take place during northern hemisphere summer time (Jun-Jul-Aug). This is also likely to be correlated with the increased numbers of flights during the summer holiday period.</p>

<p>And finally, let’s look at the observations distribution by day of the week.</p>

<p>The highest frequency of accidents in a given week take place during the weekend (Sat-Sun). Again, this is also likely to be correlated with the increased numbers of flights during the summer holiday period.</p>

<h2 id="total-fatal-injuries">Total Fatal Injuries</h2>

<p>The next variable of interest relates to the Total Fatal Injuries for each observation in the dataset. This is quantified by the number of people fatally injured for each recorded observation. Let’s group the number of fatalities in buckets as shown in the plot below. Note the use of the Log10 scale for the y-axis in the plot below.</p>

<p>The bulk of the recorded accidents have a number of fatalities &lt;10 while some observations are displaying numbers of fatalities &gt;100.</p>

<h2 id="engine-types">Engine Types</h2>

<p>Next, I look at the <a href="https://en.wikipedia.org/wiki/Aircraft_engine">aircraft engine types</a> recorded in the dataset. I’ve abbreviated engine type names to improve labelling of the x-axis. Note the use of the Log10 scale for the y-axis in the plot below.</p>

<p>According to the plots above, the bulk of engine types in the reported accidents are <a href="https://en.wikipedia.org/wiki/Reciprocating_engine">Reciprocating engine</a> types which were prevalent in commercial aircraft, particularly in aircraft built during the 20th century. Recent aircraft, like the <a href="https://en.wikipedia.org/wiki/Airbus_A380#Engines">Airbus A380</a> or the Boeing <a href="https://en.wikipedia.org/wiki/Boeing_787_Dreamliner#Engines">787 Dreamliner</a> rely on <a href="https://en.wikipedia.org/wiki/Jet_engine#Turbine_powered">Jet engines</a> (e.g. TurboFan, TurboProp).</p>

<h2 id="weather-conditions">Weather Conditions</h2>

<p>Next, I look at the weather conditions recorded in the dataset. Two key aviation weather conditions to be familiar with here: <a href="http://vmc%20which%20stands%20for%20visual%20meteorological%20conditions%20and%20imc%20stands%20for%20instrument%20meteorological%20conditions./">VMC</a> which means that conditions are such that pilots have sufficient visibility to fly the aircraft maintaining visual separation from terrain and other aircraft. <a href="https://en.wikipedia.org/wiki/Instrument_meteorological_conditions">IMC</a> which means weather conditions require pilots to fly primarily by reference to instruments.</p>

<p>The bulk of accidents in the dataset take place during VMC weather conditions, which are great conditions for flying as VMC requires greater visibility and cloud clearance than IMC.</p>

<p>I imagine this would go against most people’s intuition when it comes to the relationship between weather conditions and aviation accidents. Pilots are indeed well trained to fly in all sorts of weather conditions, relying solely on the <a href="https://en.wikipedia.org/wiki/Avionics">avionics instruments</a> at their disposal.</p>

<h2 id="broad-phases-of-flight">Broad Phases of Flight</h2>

<p>Next, let’s look at the phases of flight for the recorded accidents in the dataset. According to the plot, the bulk of accidents took place during landing or take-off. It is well known in the industry that these are high-risk — often referred to as “<a href="http://aviationknowledge.wikidot.com/sop:critical-phases-of-flights">critical phases of flight</a>”.</p>

<p><img src="https://unsplash.com/photos/WKOKyXrKnJc/download?force=true&amp;w=800" alt="Flight phases analysis" />
<em>Take-off and landing are the most critical phases of flight</em></p>

<h1 id="bivariate-plots-section">Bivariate Plots Section</h1>

<p>Let’s look at the relationship between pairs of variables that could show interesting relationships.</p>

<h2 id="engine-types-and-total-fatal-injuries">Engine Types and Total Fatal Injuries</h2>

<p>The bulk of the distribution has a total fatal injuries under 10, let’s zoom in on that portion of the data. The R function <a href="http://ggplot2.tidyverse.org/reference/geom_jitter.html">geom_jitter</a> was used to amplify the visualisation of the data points.</p>

<p>According to the plot, the bulk of the data for fatalities under 10 is with the engine type <a href="https://en.wikipedia.org/wiki/Reciprocating_engine">reciprocating engine</a> type. The first plot shows that the Turbo-Fan engine has more outliers with higher number of fatalities than other engines. This is likely correlated to the use of Turbo-Fan engines use on large commercial aircraft.</p>

<h2 id="weather-conditions-and-total-fatal-injuries">Weather Conditions and Total Fatal Injuries</h2>

<p>As previously noted, weather conditions do not show a particularly strong relationship with total fatal injuries. The bulk of the distribution is associated with VMC weather conditions. However, that is likely due to the fact that the vast majority of flights are flown in VMC conditions.</p>

<h2 id="phase-of-flight-and-total-fatal-injuries">Phase of Flight and Total Fatal Injuries</h2>

<p>Let’s look at the relationship of Phase of Flight and Total Fatal Injuries.</p>

<p>The plots show that Take-Off and Approach are associated with outliers with high number of fatalities. As previously noted, these two phases of flight are often referred to as “<a href="http://aviationknowledge.wikidot.com/sop:critical-phases-of-flights">critical phases of flight</a>” for that particular reason.</p>

<h2 id="event-month-and-weekday-and-total-fatal-injuries">Event Month and Weekday and Total Fatal Injuries</h2>

<p>Let’s look at the relationship of Event Date and Total Fatal Injuries. We’ll focus on the bulk of the distribution with fatalities of less than 10. There doesn’t seem to be any specific month or weekday showing a particularly high frequency of accidents.</p>

<h2 id="broad-phase-of-flight-and-weather-conditions">Broad Phase of Flight and Weather Conditions</h2>

<p>The plots indicate that there is higher frequency of recorded observations for certain combinations of weather and phases of flight — for example, IMC flying conditions while during “cruise” or “approach” phases of flight.</p>

<h2 id="broad-phase-of-flight-and-event-month">Broad Phase of Flight and Event Month</h2>

<p>The plots indicate that there is a higher frequency of recorded observations for Northern summer months during Landing and Take-off. Across all months, the heat map also shows that the Take-off and Landing register the highest number of observations.</p>

<h2 id="longitude-and-latitude-of-recorded-accidents">Longitude and Latitude of Recorded Accidents</h2>

<p>Plotting the Latitude vs Longitude of the accidents essentially gives us the map of the US. The plots also indicate that the coastal states are more heavily impacted compared to mid-western states and most of Alaska. This can be explained by the volume of flights to/from destinations in those areas of the US. A sad chart however as it shows that the vast majority of US States suffered an aviation tragedy between 1948 and 2017.</p>

<h1 id="multivariate-plots-section">Multivariate Plots Section</h1>

<p>Now let’s look at multivariate plots.</p>

<h2 id="latitude-vs-longitude-of-observations-by-month-of-the-year">Latitude vs Longitude of observations by Month of the Year</h2>

<p>The distribution of accident months across latitude and longitude is fairly spread across the US, with a slightly higher prevalence of observations during the winter in southern states like Florida.</p>

<h2 id="longitude-and-latitude-by-weather-conditions">Longitude and Latitude by Weather Conditions</h2>

<p>Let’s now look at latitude vs longitude add layer for the weather condition.</p>

<p>Weather condition VMC seems to be quite consistent except for patches of primarily IMC conditions for certain discrete areas of the mid-west.</p>

<h2 id="broad-phase-of-flight-and-event-month-by-weather-conditions">Broad Phase of Flight and Event Month by Weather Conditions</h2>

<p>Let’s now look at the relationship of Broad Phase of Flight vs Month by Weather Conditions. I decided to leave the observations with “unknown” weather conditions as there is what I perceive to be non-negligible number of observations, particularly for the “Cruise” phase of flight.</p>

<p>When looking at the relationship between Broad Phase of Flight vs Month and Weather Condition, we can see that accidents primarily take place during VMC weather conditions. However, for certain months of the year such as December and January, IMC conditions are a non-negligible portion of the observations, particularly during Approach and Cruise phases of flight.</p>

<h2 id="total-fatal-injuries-and-broad-phases-of-flight-by-weather-condition">Total Fatal Injuries and Broad Phases of Flight by Weather Condition</h2>

<p>Next, let’s look at Total Fatal Injuries vs Broad Phases of Flight by Weather Condition. I decided to focus on total fatal injuries of less than 40 to highlight the bulk of the distribution of recorded fatal injuries.</p>

<p>IMC weather conditions are associated with accidents during “Cruise” and “Approach” phases of flight with higher frequencies than in VMC weather conditions.</p>

<h2 id="total-fatal-injuries-and-engine-type-by-year">Total Fatal Injuries and Engine Type by Year</h2>

<p>This plot is interesting as it shows how certain engines have become prevalent in different time periods. For instance, Turbo-Jet and Turbo-Fan powered aircraft show a higher number of fatalities in later years whereas reciprocating engines show a distribution of fatalities in earlier years, this corresponds to the increasing use of jet engines in modern aircraft.</p>

<p><img src="https://unsplash.com/photos/6ArTTluciuA/download?force=true&amp;w=800" alt="Aviation technology evolution" />
<em>Evolution of aviation technology reflected in accident data</em></p>

<h1 id="concluding-remarks">Concluding Remarks</h1>

<p>I hope you enjoyed this EDA and learned a few things about aviation along the way. I hope that this post also shows the power of simple data visualisations with <a href="https://www.statmethods.net/advgraphs/ggplot2.html">ggplot2 in R</a>. This skill is particularly useful when exploring a dataset in the initial phase of the <a href="https://towardsdatascience.com/a-beginners-guide-to-the-data-science-pipeline-a4904b2d8ad3">data science pipeline</a>. I certainly enjoyed this fun little study done over the weekend.</p>

<p><strong>Key Findings:</strong></p>
<ul>
  <li>Aviation accidents have decreased by ~47% from 1982 to 2017</li>
  <li>Most accidents occur during summer months and weekends (higher flight volume)</li>
  <li>Landing and take-off remain the most critical phases of flight</li>
  <li>Counterintuitively, most accidents occur in good weather conditions (VMC)</li>
  <li>Engine technology evolution is clearly visible in the accident patterns over time</li>
</ul>

<hr />

<p><em>If you found this article helpful, feel free to connect with me on <a href="https://linkedin.com/in/hamzabendemra" target="_blank" rel="noopener">LinkedIn</a> or check out my other articles on <a href="https://medium.com/@hamzabendemra" target="_blank" rel="noopener">Medium</a>.</em></p>]]></content><author><name></name></author><category term="data-science" /><category term="data-analysis" /><category term="r" /><category term="data-visualization" /><category term="exploratory-data-analysis" /><category term="ggplot2" /><category term="aviation" /><category term="data-analysis" /><category term="ntsb" /><summary type="html"><![CDATA[An in-depth exploratory data analysis of aviation accidents in the US from 1948-2017 using R and ggplot2, examining relationships between weather conditions, phases of flight, engine types, and fatalities using NTSB data.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://bendemra.ai/assets/images/posts/aviation-analysis.jpg" /><media:content medium="image" url="https://bendemra.ai/assets/images/posts/aviation-analysis.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>