Challenge

Project 2 - EDA on Vehicle Insurance Customer Data

EDA on Vehicle Insurance Customer Data

In [1]:
# importing the required libraries

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

1. Adding the column names to both datasets while reading them:

In [2]:
## The "customer details" file is read and is given the column headings

table1 = pd.read_csv("customer_details.csv")
table1.columns=["Customer_id","Gender","Age","Driving_license_present","Region_Code","Previously_insured","Vehicle_age","Vehicle_damage"]
In [3]:
#To look at the customer details table
table1
Out[3]:
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 [4]:
## The "customer_policy_details.csv file is read and the column names are given


table2 = pd.read_csv("customer_policy_details.csv")
table2.columns=["Customer_id", "Annual_premium", "Sales_Channel_Code", "Vintage", "Response" ]
In [5]:
#To look at the customer policy details table
table2
Out[5]:
Customer_id Annual_premium 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:

i.Scanning for Null values and cleaning if any present

In [6]:
# For table1

# Generating a summary of count of all the null values column wise for table 1

table1.isnull().sum()
Out[6]:
Customer_id                386
Gender                     368
Age                        368
Driving_license_present    393
Region_Code                392
Previously_insured         381
Vehicle_age                381
Vehicle_damage             407
dtype: int64
In [7]:
# Drop Null values for customer_id because central tendencies for id’s is not feasible

table1 = table1[~table1.Customer_id.isnull()].copy()


table1.isnull().sum()


table1
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

380723 rows × 8 columns

In [8]:
# Replace all null values for numeric columns by mean for table 1

#numeric data
age_mean = table1['Age'].mean()
table1['Age'].fillna(value=age_mean,inplace=True)

region_mean = table1['Region_Code'].mean()
table1['Region_Code'].fillna(value=region_mean,inplace=True)
In [10]:
table1
Out[10]:
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

380723 rows × 8 columns

In [11]:
# Replace all null values for Categorical value by mode for table 1

#categorical data

gender_mode=table1.Gender.mode()[0]
table1.Gender.fillna(gender_mode,inplace=True)

driving_license_present_mode=table1.Driving_license_present.mode()[0]
table1.Driving_license_present.fillna(driving_license_present_mode,inplace=True)

previously_insured_mode=table1.Previously_insured.mode()[0]
table1.Previously_insured.fillna(previously_insured_mode,inplace=True)

vehicle_damage_mode=table1.Vehicle_damage.mode()[0]
table1.Vehicle_damage.fillna(vehicle_damage_mode,inplace=True)

vehicle_age_mode=table1.Vehicle_age.mode()[0]
table1.Vehicle_age.fillna(vehicle_age_mode,inplace=True)


table1.isnull().sum()



table1.describe()
Out[11]:
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 [12]:
# # For table2:
# Generating a summary of count of all the null values column wise

table2.isnull().sum()
Out[12]:
Customer_id           387
Annual_premium        346
Sales_Channel_Code    400
Vintage               388
Response              361
dtype: int64
In [13]:
# Drop Null values for customer_id because central tendencies for id’s is not feasible

table2 = table2[~table2.Customer_id.isnull()].copy()

table2.isnull().sum()
Out[13]:
Customer_id             0
Annual_premium        344
Sales_Channel_Code    400
Vintage               388
Response              361
dtype: int64
In [14]:
# Replace all null values for numeric columns by mean for table 2

#numeric data
annual_mean = table2['Annual_premium'].mean()
table2['Annual_premium'].fillna(value=annual_mean,inplace=True)

sales_channel_mean = table2['Sales_Channel_Code'].mean()
table2['Sales_Channel_Code'].fillna(value=sales_channel_mean,inplace=True)

vintage_mean = table2['Vintage'].mean()
table2['Vintage'].fillna(value=vintage_mean,inplace=True)
In [15]:
table2
Out[15]:
Customer_id Annual_premium 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

380722 rows × 5 columns

In [16]:
# Replace all null values for Categorical value by mode for table 2

#categorical data

response_mode=table2.Response.mode()[0]
table2.Response.fillna(response_mode,inplace=True)


table2.isnull().sum()


table2.describe()
Out[16]:
Customer_id Annual_premium Sales_Channel_Code Vintage Response
count 380722.000000 380722.000000 380722.000000 380722.000000 380722.000000
mean 190547.491663 30563.999774 112.036687 154.347192 0.122410
std 110013.824148 17190.147550 54.177046 83.628096 0.327759
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

Outliers detection For table1

In [17]:
# Age Outliers detection

x= table1.describe()["Age"]

IQR_age= x["75%"]-x["25%"]

table1[table1["Age"]<x["25%"]-1.5*IQR_age]

table1[table1["Age"]>x["75%"]+1.5*IQR_age]



# Region Code Outlier detection

y= table1.describe()["Region_Code"]

IQR_rc= y["75%"]-y["25%"]

table1[table1["Region_Code"]<x["25%"]-1.5*IQR_rc]

table1[table1["Region_Code"]>x["75%"]+1.5*IQR_rc]
Out[17]:
Customer_id Gender Age Driving_license_present Region_Code Previously_insured Vehicle_age Vehicle_damage
In [18]:
table1
Out[18]:
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

380723 rows × 8 columns

Outliers detection For table2:

In [20]:
# Annual Premium outlier detection 

x= table2.describe()["Annual_premium"]

IQR_ap= x["75%"]-x["25%"]

table2[table2["Annual_premium"]<x["25%"]-1.5*IQR_ap]

table2[table2["Annual_premium"]>x["75%"]+1.5*IQR_ap]

mean = table2["Annual_premium"].mean()
upper_outliers = table2["Annual_premium"]>x["75%"]+1.5*IQR_ap

mean
table2.loc[upper_outliers,"Annual_premium"]=np.nan
table2["Annual_premium"].fillna(mean,inplace=True)

table2[table2["Annual_premium"]>x["75%"]+1.5*IQR_ap]
Out[20]:
Customer_id Annual_premium Sales_Channel_Code Vintage Response
In [21]:
# Sales Channel Code Outlier detection

x= table2.describe()["Sales_Channel_Code"]

IQR_scc= x["75%"]-x["25%"]

table2[table2["Sales_Channel_Code"]<x["25%"]-1.5*IQR_scc]

table2[table2["Sales_Channel_Code"]>x["75%"]+1.5*IQR_scc]
Out[21]:
Customer_id Annual_premium Sales_Channel_Code Vintage Response
In [22]:
# Vintage Outlier Detection

x= table2.describe()["Vintage"]

IQR_v= x["75%"]-x["25%"]

table2[table2["Vintage"]<x["25%"]-1.5*IQR_v]


table2[table2["Vintage"]>x["75%"]+1.5*IQR_v]
Out[22]:
Customer_id Annual_premium Sales_Channel_Code Vintage Response

iii. Removing White spaces

In [23]:
table1.head()


table1['Vehicle_age'].str.replace(' ','')
table1['Gender'].str.replace(' ','')
table1['Vehicle_damage'].replace(' ','')
table1
Out[23]:
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

380723 rows × 8 columns

iv. case correction. Convert string values to uppercase

In [24]:
table1["Gender"]=table1["Gender"].str.upper()
table1["Vehicle_damage"]=table1["Vehicle_damage"].str.upper()

table1.sample(10)
Out[24]:
Customer_id Gender Age Driving_license_present Region_Code Previously_insured Vehicle_age Vehicle_damage
131046 131047.0 MALE 25.0 1.0 41.0 1.0 < 1 Year NO
116643 116644.0 MALE 23.0 1.0 28.0 1.0 < 1 Year NO
178081 178082.0 FEMALE 23.0 1.0 8.0 1.0 < 1 Year NO
371603 371604.0 FEMALE 71.0 1.0 33.0 0.0 1-2 Year YES
238765 238766.0 MALE 65.0 1.0 28.0 0.0 1-2 Year YES
47911 47912.0 MALE 38.0 1.0 22.0 0.0 1-2 Year YES
313415 313416.0 FEMALE 24.0 1.0 8.0 1.0 < 1 Year NO
79924 79925.0 FEMALE 25.0 1.0 21.0 1.0 < 1 Year NO
358882 358883.0 FEMALE 46.0 1.0 22.0 0.0 1-2 Year NO
190166 190167.0 FEMALE 55.0 1.0 28.0 0.0 1-2 Year YES

v. Convert nominal data (categorical) into dummies

In [25]:
# for future modeling use if required 
 

table1_d=pd.get_dummies(table1, columns=['Gender','Vehicle_damage','Driving_license_present','Previously_insured','Vehicle_age'])


table2_d=pd.get_dummies(table2,columns=['Response'])

vi. Droping Duplicates (duplicated rows)

In [26]:
table1.drop_duplicates(inplace=True)
table1_d.drop_duplicates(inplace=True) #table1 with the dummy columns


table2.drop_duplicates(inplace=True)
table2_d.drop_duplicates(inplace=True) #table2 with the dummy columns

3. Create a Master table for future use. Join the customer table and customer_policy table

In [27]:
# to get a master table using customer_id in both tables.


table_merge=pd.merge(table1,table2,on='Customer_id')


table_merge_d=pd.merge(table1_d,table2_d,on="Customer_id") #this is a merged table for the dummies table


table_merge


table_merge_d.describe()


table_merge.describe()
Out[27]:
Customer_id Age Driving_license_present Region_Code Previously_insured Annual_premium Sales_Channel_Code Vintage Response
count 380336.000000 380336.000000 380336.000000 380336.000000 380336.000000 380336.000000 380336.000000 380336.000000 380336.000000
mean 190541.253954 38.822339 0.997868 26.389690 0.457811 29300.333246 112.037616 154.353300 0.122423
std 110013.789585 15.505135 0.046128 13.223789 0.498218 14532.972093 54.176953 83.630142 0.327775
min 1.000000 20.000000 0.000000 0.000000 0.000000 2630.000000 1.000000 10.000000 0.000000
25% 95267.750000 25.000000 1.000000 15.000000 0.000000 24416.000000 29.000000 82.000000 0.000000
50% 190524.500000 36.000000 1.000000 28.000000 0.000000 30949.000000 131.000000 154.000000 0.000000
75% 285809.250000 49.000000 1.000000 35.000000 1.000000 38336.000000 152.000000 227.000000 0.000000
max 381109.000000 85.000000 1.000000 52.000000 1.000000 61854.000000 163.000000 299.000000 1.000000

4. Gaining insights from the data for future growth of the insurance company

In [28]:
# The following information are collected:

# i. Gender wise average annual premium: To find the gender who have taken the most policies from the company so we can 
# find ways to further increase the number

table_merge.groupby('Gender')['Annual_premium'].mean()
Out[28]:
Gender
FEMALE    29273.474247
MALE      29323.099677
Name: Annual_premium, dtype: float64
In [29]:
# # ii. Age wise average annual premium: The result is plotted as a graph to get visualized result of the age distribution
# of the policy holder's average annual premium 

age_plot= table_merge.groupby('Age')['Annual_premium'].mean()
age_plot.plot()
plt.show()


age_plot  #age wise average annual premium
Out[29]:
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, Length: 67, dtype: float64
In [31]:
#iii. Finding if the data is balanced between the two genders

print("Proportion of Males in data: ", table_merge_d[table_merge_d["Gender_MALE"]==1].shape[0]/table_merge_d.shape[0]*100)


print("Proportion Females in data:",table_merge_d[table_merge_d["Gender_FEMALE"]==1].shape[0]/table_merge_d.shape[0]*100)
Proportion of Males in data:  54.123459257077954
Proportion Females in data: 45.87654074292205
In [32]:
#iv. Vehicle age wise average annual premium.

table_merge.groupby('Vehicle_age')['Annual_premium'].mean()


vehicle_age_plot= table_merge.groupby('Vehicle_age')['Annual_premium'].mean()
vehicle_age_plot.plot()
plt.show()

5. Is there any relation between Person Age and annual premium?

In [33]:
# # Is there any relation between Person Age and annual premium?

n = table_merge["Age"].corr(table_merge["Annual_premium"])


if n<-0.5:
    print("Strong negative relationship")
elif n>0.5:
    print("Strong positive relationship")
elif n>-0.5 and n <0.5:
    print("There is no relationship")


table_merge.to_csv('table_merge.csv',index=False)
There is no relationship
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.