Challenge

Project 2 - EDA on Vehicle Insurance Customer Data

Project - 2 :

EDA on Vehicle Insurance Customer Data

A company has customer data that contains 8 columns of customer details and another table having name customer_policy data contains the policy details of the customer.

The company intends to offer some discount in premium for certain customers. To do that they ask their Data scientist team to get some information. Hence, following tasks DS team decided to perform:

In [1]:
# import

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

1.Adding column names to both datasets

In [2]:
# ================Loading data into files===============================

df1=pd.read_csv("customer_details.csv")
In [3]:
df1  # printing customer details table
Out[3]:
0 1 2 3 4 5 6 7
0 1.0 Male 44.0 1.0 28.0 0.0 > 2 Years Yes
1 2.0 Male 76.0 1.0 3.0 0.0 1-2 Year No
2 3.0 Male 47.0 1.0 28.0 0.0 > 2 Years Yes
3 4.0 Male 21.0 1.0 11.0 1.0 < 1 Year No
4 5.0 Female 29.0 1.0 41.0 1.0 < 1 Year No
... ... ... ... ... ... ... ... ...
381104 381105.0 Male 74.0 1.0 26.0 1.0 1-2 Year No
381105 381106.0 Male 30.0 1.0 37.0 1.0 < 1 Year No
381106 381107.0 Male 21.0 1.0 30.0 1.0 < 1 Year No
381107 381108.0 Female 68.0 1.0 14.0 0.0 > 2 Years Yes
381108 381109.0 Male 46.0 1.0 29.0 0.0 1-2 Year No

381109 rows × 8 columns

In [4]:
df2=pd.read_csv("customer_policy_details.csv")
In [5]:
df2  #printing customer policy details table
Out[5]:
0 1 2 3 4
0 1.0 40454.0 26.0 217.0 1.0
1 2.0 33536.0 26.0 183.0 0.0
2 3.0 38294.0 26.0 27.0 1.0
3 4.0 28619.0 152.0 203.0 0.0
4 5.0 27496.0 152.0 39.0 0.0
... ... ... ... ... ...
381104 381105.0 30170.0 26.0 88.0 0.0
381105 381106.0 40016.0 152.0 131.0 0.0
381106 381107.0 35118.0 160.0 161.0 0.0
381107 381108.0 44617.0 124.0 74.0 0.0
381108 381109.0 41777.0 26.0 237.0 0.0

381109 rows × 5 columns

In [6]:
# 1...(1)~ Adding coulumn names to customer details table-

df1.columns= ['customer_id','Gender','Age','Driving license present','region code','previously insured','vehicle age','vehicle damage']
In [7]:
df1     # Printing the customer policy table with column names
Out[7]:
customer_id Gender Age Driving license present region code previously insured vehicle age vehicle damage
0 1.0 Male 44.0 1.0 28.0 0.0 > 2 Years Yes
1 2.0 Male 76.0 1.0 3.0 0.0 1-2 Year No
2 3.0 Male 47.0 1.0 28.0 0.0 > 2 Years Yes
3 4.0 Male 21.0 1.0 11.0 1.0 < 1 Year No
4 5.0 Female 29.0 1.0 41.0 1.0 < 1 Year No
... ... ... ... ... ... ... ... ...
381104 381105.0 Male 74.0 1.0 26.0 1.0 1-2 Year No
381105 381106.0 Male 30.0 1.0 37.0 1.0 < 1 Year No
381106 381107.0 Male 21.0 1.0 30.0 1.0 < 1 Year No
381107 381108.0 Female 68.0 1.0 14.0 0.0 > 2 Years Yes
381108 381109.0 Male 46.0 1.0 29.0 0.0 1-2 Year No

381109 rows × 8 columns

In [8]:
# 1...(2)~ Adding columns to the customer policy details table

df2.columns=['customer_id','annual premium (in Rs)','sales channel code','vintage','response']
In [9]:
df2    # Printing the customer policy table with column names
Out[9]:
customer_id annual premium (in Rs) sales channel code vintage response
0 1.0 40454.0 26.0 217.0 1.0
1 2.0 33536.0 26.0 183.0 0.0
2 3.0 38294.0 26.0 27.0 1.0
3 4.0 28619.0 152.0 203.0 0.0
4 5.0 27496.0 152.0 39.0 0.0
... ... ... ... ... ...
381104 381105.0 30170.0 26.0 88.0 0.0
381105 381106.0 40016.0 152.0 131.0 0.0
381106 381107.0 35118.0 160.0 161.0 0.0
381107 381108.0 44617.0 124.0 74.0 0.0
381108 381109.0 41777.0 26.0 237.0 0.0

381109 rows × 5 columns

2.Checking and Cleaning Data Quality

In [10]:
'''
2) Checking and cleaning data quality

 i) Null Values

    a) ~ Generating the summary of count all the null values column wise for customer details table
'''

df1_null = df1.isnull()
print(' n True = Null values in customer details table,n -------------------- n False = Not Null values in customer details table : n ------------------')
for i in df1_null.columns.values.tolist():
    print(i)
    print("-"*26)
    print(df1_null[i].value_counts())
    print("-"*26)
 
 True = Null values in customer details table,
 -------------------- 
 False = Not Null values in customer details table : 
 ------------------
customer_id
--------------------------
False    380723
True        386
Name: customer_id, dtype: int64
--------------------------
Gender
--------------------------
False    380741
True        368
Name: Gender, dtype: int64
--------------------------
Age
--------------------------
False    380741
True        368
Name: Age, dtype: int64
--------------------------
Driving license present
--------------------------
False    380716
True        393
Name: Driving license present, dtype: int64
--------------------------
region code
--------------------------
False    380717
True        392
Name: region code, dtype: int64
--------------------------
previously insured
--------------------------
False    380728
True        381
Name: previously insured, dtype: int64
--------------------------
vehicle age
--------------------------
False    380728
True        381
Name: vehicle age, dtype: int64
--------------------------
vehicle damage
--------------------------
False    380702
True        407
Name: vehicle damage, dtype: int64
--------------------------

~ SUMMARY OF NULL VALUES ON CUSTOMER DETAILS TABLE ~

Customer_Id has 386 Null values

Gender has 368 Null values

age has 368 Null values

driving license present has 393 Null values

region code has 392 Null values

previously insured has 381 Null values

vehicle age has 381 Null values

vehicle damage has 407 Null values

In [11]:
'''
2)-i) Null Values

      a) ~ Generating the summmary of couunt all the null values column wise for customer-policy-details table
'''
df2_null = df2.isnull()
print(' n True = Null values in customer-policy-details table,n -------------------- n False = Not Null values in customer-policy- details table : n ------------------')
for i in df2_null.columns.values.tolist():
    print(i)
    print("-"*26)
    print(df2_null[i].value_counts())
    print("-"*26)
 
 True = Null values in customer-policy-details table,
 -------------------- 
 False = Not Null values in customer-policy- details table : 
 ------------------
customer_id
--------------------------
False    380722
True        387
Name: customer_id, dtype: int64
--------------------------
annual premium (in Rs)
--------------------------
False    380763
True        346
Name: annual premium (in Rs), dtype: int64
--------------------------
sales channel code
--------------------------
False    380709
True        400
Name: sales channel code, dtype: int64
--------------------------
vintage
--------------------------
False    380721
True        388
Name: vintage, dtype: int64
--------------------------
response
--------------------------
False    380748
True        361
Name: response, dtype: int64
--------------------------

~ SUMMARY OF NULL VALUES ON CUSTOMER -POLICY- DETAILS TABLE ~

Customer_Id has 387 Null values

annual premium has 346 Null values

sales channel code has 400 Null values

vintage has 388 Null values

response has 361 Null values

In [12]:
# 2).i) Null Values
#       b) ~ Dropping Null Values for Customer _id for customer details table


df1.dropna(subset=['customer_id'],inplace=True)
In [13]:
print(' customer details table n Null values in customer_id column after dropping  null values :',df1['customer_id'].isna().sum())
 customer details table 
 Null values in customer_id column after dropping  null values : 0
In [14]:
# 2).i) Null Values
#       b) ~ Dropping Null Values for Customer _id in customer-policy-details table

df2.dropna(subset=['customer_id'],inplace=True)
In [15]:
print(' customer-policy-details table n Null values in customer_id column after dropping  null values :',df2['customer_id'].isna().sum())
 customer-policy-details table 
 Null values in customer_id column after dropping  null values : 0
In [16]:
'''
2).i)Null Values

c) Replace all values for numeric columns by mean 

'''
df1.head()
Out[16]:
customer_id Gender Age Driving license present region code previously insured vehicle age vehicle damage
0 1.0 Male 44.0 1.0 28.0 0.0 > 2 Years Yes
1 2.0 Male 76.0 1.0 3.0 0.0 1-2 Year No
2 3.0 Male 47.0 1.0 28.0 0.0 > 2 Years Yes
3 4.0 Male 21.0 1.0 11.0 1.0 < 1 Year No
4 5.0 Female 29.0 1.0 41.0 1.0 < 1 Year No

From customer details table,

age and region code contains numerical data

driving license present and previously insured contains categorical data

In [16]:
# Replacing the null values of age by its mean value

df1['Age'].fillna(df1['Age'].mean(),inplace=True)
In [17]:
print(' Null values in Age column after dropping  null values :',df1['Age'].isna().sum())
 Null values in Age column after dropping  null values : 0
In [18]:
# Replacing the null values of region code by its mean value

df1['region code'].fillna(df1['region code'].mean(),inplace=True)
In [19]:
print(' Null values in region code column after dropping  null values :',df1['region code'].isna().sum())
 Null values in region code column after dropping  null values : 0
In [20]:
df2.head()
Out[20]:
customer_id annual premium (in Rs) sales channel code vintage response
0 1.0 40454.0 26.0 217.0 1.0
1 2.0 33536.0 26.0 183.0 0.0
2 3.0 38294.0 26.0 27.0 1.0
3 4.0 28619.0 152.0 203.0 0.0
4 5.0 27496.0 152.0 39.0 0.0

From customer-policy-details table,

annual premium, sales channel code and vintage contains numerical data

response has categorical data

In [21]:
# Replacing the null values of annual premium by its mean value

df2['annual premium (in Rs)'].fillna(df2['annual premium (in Rs)'].mean(),inplace=True)
In [22]:
print(' Null values in annual premium (in Rs) column after dropping  null values :',df2['annual premium (in Rs)'].isna().sum())
 Null values in annual premium (in Rs) column after dropping  null values : 0
In [23]:
# Replacing the null values of channel code by its mean value

df2['sales channel code'].fillna(df2['sales channel code'].mean(),inplace=True)
In [24]:
print(' Null values in sales channel code column after dropping  null values :',df2['sales channel code'].isna().sum())
 Null values in sales channel code column after dropping  null values : 0
In [25]:
# Replacing the null values of vintage by its mean value

df2['vintage'].fillna(df2['vintage'].mean(),inplace=True)
In [26]:
print(' Null values in vintage column after dropping  null values :',df2['vintage'].isna().sum())
 Null values in vintage column after dropping  null values : 0
In [27]:
'''
2).i)Null Values

    d) Replacing categorical null values by its mode

'''
# Replacing the null values of driving license present by its mode value

df1['Driving license present'].fillna(df1['Driving license present'].mode()[0],inplace=True)
In [28]:
print(' Null values in Driving license present column after dropping  null values :',df1['Driving license present'].isna().sum())
 Null values in Driving license present column after dropping  null values : 0
In [29]:
# Replacing the null values of previously insured by its mode value

df1['previously insured'].fillna(df1['previously insured'].mode()[0],inplace=True)
In [30]:
print(' Null values in previously insured column after dropping  null values :',df1['previously insured'].isna().sum())
 Null values in previously insured column after dropping  null values : 0
In [31]:
# Replacing the null values of vintage by its mode value

df2['vintage'].fillna(df2['vintage'].mode()[0],inplace=True)
In [32]:
print(' Null values in previously insured column after dropping  null values :',df2['vintage'].isna().sum())
 Null values in previously insured column after dropping  null values : 0
In [33]:
'''
2.(ii). OUTLIERS

a) Generate the summary of count of all the null values column wise

'''
df1.describe()
Out[33]:
customer_id Age Driving license present region code previously insured
count 380723.000000 380723.000000 380723.000000 380723.000000 380723.000000
mean 190548.776244 38.822788 0.997870 26.389436 0.457800
std 110016.805160 15.504826 0.046105 13.223671 0.498217
min 1.000000 20.000000 0.000000 0.000000 0.000000
25% 95269.500000 25.000000 1.000000 15.000000 0.000000
50% 190543.000000 36.000000 1.000000 28.000000 0.000000
75% 285822.500000 49.000000 1.000000 35.000000 1.000000
max 381109.000000 85.000000 1.000000 52.000000 1.000000
In [34]:
Q1=df1.describe().loc["25%","Age"]
Q3=df1.describe().loc["75%","Age"]

IQR=Q3-Q1

print('Customer details table')
print('Outliers present in age column are :',df1.loc[df1["Age"]<(Q1-IQR*1.5),"Age"].count())
print('Outliers present in age column are :',df1.loc[df1["Age"]>(Q3+IQR*1.5),"Age"].count())
Customer details table
Outliers present in age column are : 0
Outliers present in age column are : 0
In [35]:
Q1=df1.describe().loc["25%","region code"]
Q3=df1.describe().loc["75%","region code"]

IQR=Q3-Q1

print('Customer details table')
print('Outliers present in region code column are :',df1.loc[df1["region code"]<(Q1-IQR*1.5),"region code"].count())
print('Outliers present in region code column are :',df1.loc[df1["region code"]>(Q3+IQR*1.5),"region code"].count())
Customer details table
Outliers present in region code column are : 0
Outliers present in region code column are : 0
In [36]:
df2.describe()
Out[36]:
customer_id annual premium (in Rs) sales channel code vintage response
count 380722.000000 380722.000000 380722.000000 380722.000000 380361.000000
mean 190547.491663 30563.999774 112.036687 154.347192 0.122526
std 110013.824148 17190.147550 54.177046 83.628096 0.327892
min 1.000000 2630.000000 1.000000 10.000000 0.000000
25% 95276.250000 24416.000000 29.000000 82.000000 0.000000
50% 190536.500000 31656.000000 131.000000 154.000000 0.000000
75% 285818.750000 39391.750000 152.000000 227.000000 0.000000
max 381109.000000 540165.000000 163.000000 299.000000 1.000000
In [37]:
Q1=df2.describe().loc["25%","annual premium (in Rs)"]
Q3=df2.describe().loc["75%","annual premium (in Rs)"]

IQR=Q3-Q1

print('Customer-policy-details table')
print('Outliers present in annual premium (in Rs)  column are :',df2.loc[df2["annual premium (in Rs)"]<(Q1-IQR*1.5),"annual premium (in Rs)"].count())
print('Outliers present in annual premium (in Rs)  column are :',df2.loc[df2["annual premium (in Rs)"]>(Q3+IQR*1.5),"annual premium (in Rs)"].count())
Customer-policy-details table
Outliers present in annual premium (in Rs)  column are : 0
Outliers present in annual premium (in Rs)  column are : 10332
In [38]:
Q1=df2.describe().loc["25%","vintage"]
Q3=df2.describe().loc["75%","vintage"]

IQR=Q3-Q1

print('Customer-policy-details table')
print('Outliers present in vintage column are :',df2.loc[df2["vintage"]<(Q1-IQR*1.5),"vintage"].count())
print('Outliers present in vintage column are :',df2.loc[df2["vintage"]>(Q3+IQR*1.5),"vintage"].count())
Customer-policy-details table
Outliers present in vintage column are : 0
Outliers present in vintage column are : 0
In [39]:
'''
2.(ii).
 
 (b) Replacing the outliers with mean values

'''
# We are replacing the outliers of annual premium (in Rs) column with mean values in customer-policy-details table


mean=df2["annual premium (in Rs)"].mean()
In [40]:
print('Mean of annual premium (in Rs) column values: ',mean)
Mean of annual premium (in Rs) column values:  30563.99977390893
In [41]:
def replace_outlier(df):
    q1=df.quantile(0.25)
    q3=df.quantile(0.75)
    iqr=q3-q1
    upper=df[~(df>(q3+1.5*iqr))].max()
    lower=df[~(df<(q1-1.5*iqr))].min()
    df=np.where(df>upper,df.mean(),np.where(df<lower,df.mean(),df))
    return df
In [42]:
df2["annual premium (in Rs)"] = replace_outlier(df2["annual premium (in Rs)"])
In [43]:
df2['annual premium (in Rs)']  # Outliers are filled with mean values
Out[43]:
0         40454.0
1         33536.0
2         38294.0
3         28619.0
4         27496.0
           ...   
381104    30170.0
381105    40016.0
381106    35118.0
381107    44617.0
381108    41777.0
Name: annual premium (in Rs), Length: 380722, dtype: float64
In [45]:
'''
2).(iii)

  ~ Remove White spaces
    another way
'''

df1["Gender"]=df1["Gender"].str.strip()
df1["vehicle age"]=df1["vehicle age"].str.strip()
df1["vehicle damage"]=df1["vehicle damage"].str.strip()
In [46]:
'''
2).(iv).

    ~ Case Correction for customer details table

'''

df1["Gender"]=df1["Gender"].str.lower()
df1["vehicle age"]=df1["vehicle age"].str.lower()
df1["vehicle damage"]=df1["vehicle damage"].str.lower()
In [47]:
'''
2).(v).

    ~ Converting nominal data into dummies

'''

dummies_gender=pd.get_dummies(df1["Gender"])
dummies_vehicle_age=pd.get_dummies(df1["vehicle age"])
dummies_vehicle_damage=pd.get_dummies(df1["vehicle damage"])
dummies_dlp=pd.get_dummies(df1["Driving license present"])
dummies_pre=pd.get_dummies(df1["previously insured"])
In [48]:
# 2).(vi) Drop duplictates from customer details table

print(df1.duplicated().sum())
0
In [49]:
# 2).(vi) Drop duplictates from customer-policy-details table

print(df2.duplicated().sum())
0
In [50]:
df1.drop_duplicates(inplace=True)   #dropping duplicates
In [51]:
df2.drop_duplicates(inplace=True)   #dropping duplicates

3.Merging

In [52]:
# merging

mas_data=pd.merge(df1,df2,on='customer_id')
In [53]:
mas_data
Out[53]:
customer_id Gender Age Driving license present region code previously insured vehicle age vehicle damage annual premium (in Rs) sales channel code vintage response
0 1.0 male 44.0 1.0 28.0 0.0 > 2 years yes 40454.0 26.0 217.0 1.0
1 2.0 male 76.0 1.0 3.0 0.0 1-2 year no 33536.0 26.0 183.0 0.0
2 3.0 male 47.0 1.0 28.0 0.0 > 2 years yes 38294.0 26.0 27.0 1.0
3 4.0 male 21.0 1.0 11.0 1.0 < 1 year no 28619.0 152.0 203.0 0.0
4 5.0 female 29.0 1.0 41.0 1.0 < 1 year no 27496.0 152.0 39.0 0.0
... ... ... ... ... ... ... ... ... ... ... ... ...
380331 381105.0 male 74.0 1.0 26.0 1.0 1-2 year no 30170.0 26.0 88.0 0.0
380332 381106.0 male 30.0 1.0 37.0 1.0 < 1 year no 40016.0 152.0 131.0 0.0
380333 381107.0 male 21.0 1.0 30.0 1.0 < 1 year no 35118.0 160.0 161.0 0.0
380334 381108.0 female 68.0 1.0 14.0 0.0 > 2 years yes 44617.0 124.0 74.0 0.0
380335 381109.0 male 46.0 1.0 29.0 0.0 1-2 year no 41777.0 26.0 237.0 0.0

380336 rows × 12 columns

4. Getting required data to make decisions for future growth

In [54]:
# 4. Getting required data for decisions

# 4....1) Gender wise average annual premium

gwiseanpl=mas_data.groupby(["Gender"])["annual premium (in Rs)"].mean()
In [55]:
gwiseanpl
Out[55]:
Gender
female    29273.474247
male      29323.022594
Name: annual premium (in Rs), dtype: float64
In [56]:
# 4....2) Age wise average annual premium

agwise=mas_data.groupby(["Age"])["annual premium (in Rs)"].mean()
In [57]:
agwise
Out[57]:
Age
20.0    26342.073517
21.0    29751.791916
22.0    29946.848634
23.0    29838.344763
24.0    30125.557096
            ...     
81.0    29287.910702
82.0    36480.586199
83.0    28995.818172
84.0    35440.818182
85.0    26637.454525
Name: annual premium (in Rs), Length: 67, dtype: float64
In [58]:
# 4....3) Is your data balanced between the genders

mas_data.groupby('Gender').count()
Out[58]:
customer_id Age Driving license present region code previously insured vehicle age vehicle damage annual premium (in Rs) sales channel code vintage response
Gender
female 174485 174485 174485 174485 174485 174309 174300 174485 174485 174485 174329
male 205484 205484 205484 205484 205484 205279 205266 205484 205484 205484 205281

~ SUMMARY

The ratio between male and female is approximately 1.77

The data is balanced between the gender as the data for gender is approximately same

In [59]:
# 4....4) Vehicle age wise average plan

vwiseavp=mas_data.groupby(["vehicle age"])["annual premium (in Rs)"].mean()
In [60]:
vwiseavp
Out[60]:
vehicle age
1-2 year     29099.066738
< 1 year     29188.150594
> 2 years    32943.540830
Name: annual premium (in Rs), dtype: float64
In [61]:
vwiseavp.plot()   # line graph
Out[61]:
<AxesSubplot:xlabel='vehicle age'>

5. Checking the relation between Person Age and Annual Premium

In [62]:
# 5. Is there any relation between person age and annual premium

n=mas_data['Age'].corr(mas_data["annual premium (in Rs)"])
In [65]:
n
Out[65]:
0.0506575892861754
In [85]:
mas_data[['Age','annual premium (in Rs)']].corr()
Out[85]:
Age annual premium (in Rs)
Age 1.000000 0.050658
annual premium (in Rs) 0.050658 1.000000

~ Summary

Since the pearson coefficient lies between 0.5 and -0.5

So,there is no relation between age and annual premium (in Rs)

Kindly, review the project

Regards,

Sai Sumanth Reddy

Your portfolio, next

Ship work like this
in your own course.

Talk to a career counsellor

Free 20-minute call. We'll map the right course to where you want to work.

By submitting you agree to our Terms and Privacy Policy.

Talk to a career counsellor

Free 20-minute call. We'll map the right course to where you want to work.

By submitting you agree to our Terms and Privacy Policy.