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]:
 01234567
01.0Male44.01.028.00.0> 2 YearsYes
12.0Male76.01.03.00.01-2 YearNo
23.0Male47.01.028.00.0> 2 YearsYes
34.0Male21.01.011.01.0< 1>No
45.0Female29.01.041.01.0< 1>No
...........................
381104381105.0Male74.01.026.01.01-2 YearNo
381105381106.0Male30.01.037.01.0< 1>No
381106381107.0Male21.01.030.01.0< 1>No
381107381108.0Female68.01.014.00.0> 2 YearsYes
381108381109.0Male46.01.029.00.01-2 YearNo

381109 rows × 8 columns

In [4]:
df2=pd.read_csv("customer_policy_details.csv")

In [5]:
df2  #printing customer policy details table
Out[5]:
 01234
01.040454.026.0217.01.0
12.033536.026.0183.00.0
23.038294.026.027.01.0
34.028619.0152.0203.00.0
45.027496.0152.039.00.0
..................
381104381105.030170.026.088.00.0
381105381106.040016.0152.0131.00.0
381106381107.035118.0160.0161.00.0
381107381108.044617.0124.074.00.0
381108381109.041777.026.0237.00.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_idGenderAgeDriving license presentregion codepreviously insuredvehicle agevehicle damage
01.0Male44.01.028.00.0> 2 YearsYes
12.0Male76.01.03.00.01-2 YearNo
23.0Male47.01.028.00.0> 2 YearsYes
34.0Male21.01.011.01.0< 1>No
45.0Female29.01.041.01.0< 1>No
...........................
381104381105.0Male74.01.026.01.01-2 YearNo
381105381106.0Male30.01.037.01.0< 1>No
381106381107.0Male21.01.030.01.0< 1>No
381107381108.0Female68.01.014.00.0> 2 YearsYes
381108381109.0Male46.01.029.00.01-2 YearNo

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_idannual premium (in Rs)sales channel codevintageresponse
01.040454.026.0217.01.0
12.033536.026.0183.00.0
23.038294.026.027.01.0
34.028619.0152.0203.00.0
45.027496.0152.039.00.0
..................
381104381105.030170.026.088.00.0
381105381106.040016.0152.0131.00.0
381106381107.035118.0160.0161.00.0
381107381108.044617.0124.074.00.0
381108381109.041777.026.0237.00.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_idGenderAgeDriving license presentregion codepreviously insuredvehicle agevehicle damage
01.0Male44.01.028.00.0> 2 YearsYes
12.0Male76.01.03.00.01-2 YearNo
23.0Male47.01.028.00.0> 2 YearsYes
34.0Male21.01.011.01.0< 1>No
45.0Female29.01.041.01.0< 1>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_idannual premium (in Rs)sales channel codevintageresponse
01.040454.026.0217.01.0
12.033536.026.0183.00.0
23.038294.026.027.01.0
34.028619.0152.0203.00.0
45.027496.0152.039.00.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_idAgeDriving license presentregion codepreviously insured
count380723.000000380723.000000380723.000000380723.000000380723.000000
mean190548.77624438.8227880.99787026.3894360.457800
std110016.80516015.5048260.04610513.2236710.498217
min1.00000020.0000000.0000000.0000000.000000
25%95269.50000025.0000001.00000015.0000000.000000
50%190543.00000036.0000001.00000028.0000000.000000
75%285822.50000049.0000001.00000035.0000001.000000
max381109.00000085.0000001.00000052.0000001.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_idannual premium (in Rs)sales channel codevintageresponse
count380722.000000380722.000000380722.000000380722.000000380361.000000
mean190547.49166330563.999774112.036687154.3471920.122526
std110013.82414817190.14755054.17704683.6280960.327892
min1.0000002630.0000001.00000010.0000000.000000
25%95276.25000024416.00000029.00000082.0000000.000000
50%190536.50000031656.000000131.000000154.0000000.000000
75%285818.75000039391.750000152.000000227.0000000.000000
max381109.000000540165.000000163.000000299.0000001.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_idGenderAgeDriving license presentregion codepreviously insuredvehicle agevehicle damageannual premium (in Rs)sales channel codevintageresponse
01.0male44.01.028.00.0> 2 yearsyes40454.026.0217.01.0
12.0male76.01.03.00.01-2 yearno33536.026.0183.00.0
23.0male47.01.028.00.0> 2 yearsyes38294.026.027.01.0
34.0male21.01.011.01.0< 1>no28619.0152.0203.00.0
45.0female29.01.041.01.0< 1>no27496.0152.039.00.0
.......................................
380331381105.0male74.01.026.01.01-2 yearno30170.026.088.00.0
380332381106.0male30.01.037.01.0< 1>no40016.0152.0131.00.0
380333381107.0male21.01.030.01.0< 1>no35118.0160.0161.00.0
380334381108.0female68.01.014.00.0> 2 yearsyes44617.0124.074.00.0
380335381109.0male46.01.029.00.01-2 yearno41777.026.0237.00.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_idAgeDriving license presentregion codepreviously insuredvehicle agevehicle damageannual premium (in Rs)sales channel codevintageresponse
Gender           
female174485174485174485174485174485174309174300174485174485174485174329
male205484205484205484205484205484205279205266205484205484205484205281

 

~ 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> 2 years    32943.540830
Name: annual premium (in Rs), dtype: float64

In [61]:
vwiseavp.plot()   # line graph
Out[61]:
 

 

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]:
 Ageannual premium (in Rs)
Age1.0000000.050658
annual premium (in Rs)0.0506581.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)

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.