Skip to content


Personal loans are a lucrative revenue stream for banks. The typical interest rate of a two year loan in the United Kingdom is around 10%. This might not sound like a lot, but in September 2022 alone UK consumers borrowed around £1.5 billion, which would mean approximately £300 million in interest generated by banks over two years!

You have been asked to work with a bank to clean and store the data they collected as part of a recent marketing campaign, which aimed to get customers to take out a personal loan. They plan to conduct more marketing campaigns going forward so would like you to set up a PostgreSQL database to store this campaign's data, designing the schema in a way that would allow data from future campaigns to be easily imported.

They have supplied you with a csv file called "bank_marketing.csv", which you will need to clean, reformat, and split, in order to save separate files based on the tables you will create. It is recommended to use pandas for these tasks.

Lastly, you will write the SQL code that the bank can execute to create the tables and populate with the data from the csv files. As the bank are quite strict about their security, you'll save SQL files as multiline string variables that they can then use to create the database on their end.

You have been asked to design a database that will have three tables:

client

columndata typedescriptionoriginal column in dataset
idserialClient ID - primary keyclient_id
ageintegerClient's age in yearsage
jobtextClient's type of jobjob
maritaltextClient's marital statusmarital
educationtextClient's level of educationeducation
credit_defaultbooleanWhether the client's credit is in defaultcredit_default
housingbooleanWhether the client has an existing housing loan (mortgage)housing
loanbooleanWhether the client has an existing personal loanloan

campaign

columndata typedescriptionoriginal column in dataset
campaign_idserialCampaign ID - primary keyN/A - new column
client_idserialClient ID - references id in the client tableclient_id
number_contactsintegerNumber of contact attempts to the client in the current campaigncampaign
contact_durationintegerLast contact duration in secondsduration
pdaysintegerNumber of days since contact in previous campaign (999 = not previously contacted)pdays
previous_campaign_contactsintegerNumber of contact attempts to the client in the previous campaignprevious
previous_outcomebooleanOutcome of the previous campaignpoutcome
campaign_outcomebooleanOutcome of the current campaigny
last_contact_datedateLast date the client was contactedA combination of day, month, and the newly created year

economics

columndata typedescriptionoriginal column in dataset
client_idserialClient ID - references id in the client tableclient_id
emp_var_ratefloatEmployment variation rate (quarterly indicator)emp_var_rate
cons_price_idxfloatConsumer price index (monthly indicator)cons_price_idx
euribor_three_monthsfloatEuro Interbank Offered Rate (euribor) three month rate (daily indicator)euribor3m
number_employedfloatNumber of employees (quarterly indicator)nr_employed

Imported necessary packages

Instruction 1: Read in bank_marketing.csv

Instruction 2: Split the data into three DataFrames using information provided about the desired tables as your guide: one with information about the client, another containing campaign data, and a third to store information about economics at the time of the campaign.

  • Master DataFrame as df
  • Split the DataFrame into the specified DataFrames: client, campaign and economics
import pandas as pd
import numpy as np

df = pd.read_csv('bank_marketing.csv')
print(list(df))

client = df[['client_id', 'age', 'job', 'marital', 'education', 'credit_default', 'housing', 'loan']]
campaign = df[['client_id', 'campaign', 'duration', 'duration', 'pdays', 'previous', 'poutcome', 'y', 'day', 'month']]
economics = df[['client_id', 'emp_var_rate', 'cons_price_idx', 'euribor3m', 'nr_employed']]

Instruction 3: Rename the column "client_id" to "id" in client (leave as-is in the other subsets); "duration" to "contact_duration", "previous" to "previous_campaign_contacts", "y" to "campaign_outcome", "poutcome" to "previous_outcome", and "campaign" to "number_contacts" in campaign; and "euribor3m" to "euribor_three_months" and "nr_employed" to "number_employed" in economics.

client = client.rename(columns = {'client_id':'id'})
campaign = campaign.rename(columns = {
    'duration': 'contact_duration',
    'previous': 'previous_campaign_contacts',
    'y' : 'campaign_outcome',
    'poutcome': 'previous_outcome',
    'campaign': 'number_contacts'
})
economics = economics.rename(columns = {
    'euribor3m': 'euribor_three_months',
    'nr_employed': 'number_employed'
})

View the three DataFrames

client
campaign
economics

Instruction 3: Clean the "education" column, changing "." to "_" and "unknown" to NumPy's null values.

Instruction 4: Remove periods from the "job" column.

Instruction 5: Convert "success" and "failure" in the "previous_outcome" and "campaign_outcome" columns to binary (1 or 0), along with the changing "nonexistent" to NumPy's null values in "previous_outcome".

Instruction 6: Add a column called campaign_id in campaign, where all rows have a value of 1.

# Education column
client['education'] = client['education'].apply(lambda x: x.replace('.', '_'))
client['education'].replace('unknown', np.nan, inplace=True)

# Job column
client['job'] = client['job'].apply(lambda x: x.replace('.', ''))

# Campaign outcomes
outcome_map = {'success': 1, 'failure': 0, 'non_existent': np.nan, 'yes': 1, 'no': 0}
campaign['previous_outcome'] = campaign['previous_outcome'].map(outcome_map)
campaign['campaign_outcome'] = campaign['campaign_outcome'].map(outcome_map)

# Add column campaign_id into campaign
campaign['campaign_id'] = 1
client
campaign

Instruction 7: Create a datetime column called last_contact_date, in the format of "year-month-day", where the year is 2022, and the month and day values are taken from the "month" and "day" columns.

# Create late_contact_date of type datetime
campaign['year'] = 2022
campaign['last_contact_date'] = pd.to_datetime(
    campaign['year'].astype(str) + '-' +
    campaign['month'].astype(str) + '-' +
    campaign['day'].astype(str),
    errors='coerce'
)