Challenge

Project 2 - EDA on Vehicle Insurance Customer Data

Importing datasets and Add the column names to both datasets

In [2]:
import pandas as pd 

customer_details=pd.read_csv('customer_details.csv')
In [3]:
customer_policy_details=pd.read_csv('customer_policy_details.csv')
In [4]:
customer_details.columns=['customer_id','Gender','age','driving licence present','region code','previously insured','vehicle age','vehicle damage']
In [5]:
customer_policy_details.columns=['customer_id','annual premium (in Rs)','sales channel code','vintage','response']
 

Checking and Cleaning Data Quality:

 
Generate a summary of count of all the null values column wise
In [6]:
customer_details_null_values=customer_details.isnull()
In [7]:
customer_details_null_values_summary=customer_details_null_values.sum()
In [8]:
customer_details_null_values_summary
Out[8]:
customer_id                386
Gender                     368
age                        368
driving licence present    393
region code                392
previously insured         381
vehicle age                381
vehicle damage             407
dtype: int64
In [9]:
customer_policy_details_null_values=customer_policy_details.isnull()
In [10]:
customer_policy_details_null_values_summary=customer_policy_details_null_values.sum()
In [11]:
customer_policy_details_null_values_summary
Out[11]:
customer_id               387
annual premium (in Rs)    346
sales channel code        400
vintage                   388
response                  361
dtype: int64
 
Drop Null values for customer_id
In [12]:
customer_details.dropna(subset='customer_id',axis=0,inplace=True)
customer_details
Out[12]:
  customer_id Gender age driving licence 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> No
4 5.0 Female 29.0 1.0 41.0 1.0 < 1> 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> No
381106 381107.0 Male 21.0 1.0 30.0 1.0 < 1> 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 [13]:
customer_policy_details.dropna(subset='customer_id',axis=0,inplace=True)
customer_policy_details
Out[13]:
  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

380722 rows × 5 columns

 
Replace all null values for numeric columns by mean.
In [14]:
# in custome_details age contains the only numerical values 
mean_age=int(customer_details['age'].mean())
print(mean_age)
 
38
In [15]:
customer_details['age'].fillna(mean_age,inplace=True)
In [16]:
# in custome_policy_details annual premium (in Rs) and vintage contains the numerical values 
customer_policy_details['annual premium (in Rs)'].fillna(customer_policy_details['annual premium (in Rs)'].mean(),inplace=True)
In [17]:
mean_vintage=int(customer_policy_details['vintage'].mean())
print(mean_vintage)
 
154
In [18]:
customer_policy_details['vintage'].fillna(mean_vintage,inplace=True)
 
Replace all null values for Categorical value by mode
In [19]:
# in custome_details other than age all are categorical columns
mode_Gender=customer_details['Gender'].mode()[0]

mode_licence_present=customer_details['driving licence present'].mode()[0]

mode_region_code=customer_details['region code'].mode()[0]

mode_previously_insured=customer_details['previously insured'].mode()[0]

mode_vehicle_age=customer_details['vehicle age'].mode()[0]

mode_vehicle_damage=customer_details['vehicle damage'].mode()[0]
In [20]:
customer_details['Gender'].fillna(mode_Gender,inplace=True)
In [21]:
customer_details['driving licence present'].fillna(mode_licence_present,inplace=True)
In [22]:
customer_details['region code'].fillna(mode_region_code,inplace=True)
In [23]:
customer_details['previously insured'].fillna(mode_previously_insured,inplace=True)
In [24]:
customer_details['vehicle age'].fillna(mode_vehicle_age,inplace=True)
In [25]:
customer_details['vehicle damage'].fillna(mode_vehicle_damage,inplace=True)
In [26]:
# in custome_policy_details sales channel code and response are categorical columns
customer_policy_details['sales channel code'].fillna(customer_policy_details['sales channel code'].mode()[0],inplace=True)
customer_policy_details['response'].fillna(customer_policy_details['response'].mode()[0],inplace=True)
 
Generate a summary of count of all the outliers column wise
In [27]:
# finding outliers range for customer details
In [28]:
Q=customer_details.describe()
In [29]:
Q1=Q.loc['25%']
Q1
Out[29]:
customer_id                95269.5
age                           25.0
driving licence present        1.0
region code                   15.0
previously insured             0.0
Name: 25%, dtype: float64
In [30]:
Q3=Q.loc['75%']
Q3
Out[30]:
customer_id                285822.5
age                            49.0
driving licence present         1.0
region code                    35.0
previously insured              1.0
Name: 75%, dtype: float64
In [31]:
IQR=Q3-Q1
In [32]:
IQR
Out[32]:
customer_id                190553.0
age                            24.0
driving licence present         0.0
region code                    20.0
previously insured              1.0
dtype: float64
In [33]:
Lower_band=Q1-(1.5*(IQR))
Upper_band=Q3+(1.5*(IQR))
Lower_band
Out[33]:
customer_id               -190560.0
age                           -11.0
driving licence present         1.0
region code                   -15.0
previously insured             -1.5
dtype: float64
In [34]:
Upper_band
Out[34]:
customer_id                571652.0
age                            85.0
driving licence present         1.0
region code                    65.0
previously insured              2.5
dtype: float64
In [35]:
# count the no. of out liers
In [36]:
outliers=customer_details[(customer_details<Lower_band) | (customer_details>Upper_band)]
 
C:\Users\Shouvik\AppData\Local\Temp\ipykernel_4348\18624086.py:1: FutureWarning: Automatic reindexing on DataFrame vs Series comparisons is deprecated and will raise ValueError in a future version. Do `left, right = left.align(right, axis=1, copy=False)` before e.g. `left == right`
  outliers=customer_details[(customer_detailsUpper_band)]
In [37]:
outlier_count=outliers.count()

for i in outlier_count.index:
    print(f"The outlier for {i} is {outlier_count[i]}")
 
The outlier for customer_id is 0
The outlier for Gender is 0
The outlier for age is 0
The outlier for driving licence present is 811
The outlier for region code is 0
The outlier for previously insured is 0
The outlier for vehicle age is 0
The outlier for vehicle damage is 0
In [38]:
# it shows the outlier for driving licence present is 811 but as a categorical column it is not consided as a outlier
# We can conclude that , 811 customer don,t have a DL.
In [39]:
import matplotlib.pyplot as plt

plt.boxplot(customer_details['age'])
plt.ylabel('age')
plt.show()
 
In [40]:
# finding outliers range customer policy details
In [41]:
Qp=customer_policy_details.describe()
In [42]:
Qp1=Qp.loc['25%']
Qp1
Out[42]:
customer_id               95276.25
annual premium (in Rs)    24416.00
sales channel code           29.00
vintage                      82.00
response                      0.00
Name: 25%, dtype: float64
In [43]:
Qp3=Qp.loc['75%']
Qp3
Out[43]:
customer_id               285818.75
annual premium (in Rs)     39391.75
sales channel code           152.00
vintage                      227.00
response                       0.00
Name: 75%, dtype: float64
In [44]:
IQRp=Qp3-Qp1
In [45]:
IQRp
Out[45]:
customer_id               190542.50
annual premium (in Rs)     14975.75
sales channel code           123.00
vintage                      145.00
response                       0.00
dtype: float64
In [46]:
Lower_bandp=Qp1-(1.5*(IQRp))
Upper_bandp=Qp3+(1.5*(IQRp))
Lower_bandp
Out[46]:
customer_id              -190537.500
annual premium (in Rs)      1952.375
sales channel code          -155.500
vintage                     -135.500
response                       0.000
dtype: float64
In [47]:
Upper_bandp
Out[47]:
customer_id               571632.500
annual premium (in Rs)     61855.375
sales channel code           336.500
vintage                      444.500
response                       0.000
dtype: float64
In [48]:
# count the no. of out liers
In [49]:
outliers_p=customer_policy_details[(customer_policy_details<Lower_bandp) | (customer_policy_details>Upper_bandp)]
In [50]:
outlier_count_p=outliers_p.count()

for j in outlier_count_p.index:
    print(f"The outlier for {j} is {outlier_count_p[j]}")
 
The outlier for customer_id is 0
The outlier for annual premium (in Rs) is 10332
The outlier for sales channel code is 0
The outlier for vintage is 0
The outlier for response is 46604
In [51]:
# In 'response' values = 1.0 is counted as a outlier.
# but response' is a categorical column so that there is no outlier practically.
In [52]:
import matplotlib.pyplot as plt
# for numerical column
plt.boxplot(customer_policy_details['annual premium (in Rs)'])
plt.ylabel('annual premium (in Rs)')
plt.show()

plt.boxplot(customer_policy_details['vintage'])
plt.ylabel('vintage')
plt.show()
 
 
 
Replace all outlier values for numeric columns by mean.
In [53]:
# though we have outliers only on the 'annual premium (in Rs)' in customer policy table so we change it with the mean

outlliers_amount=(customer_policy_details[((customer_policy_details['annual premium (in Rs)'])<(Lower_bandp['annual premium (in Rs)'])) | ((customer_policy_details['annual premium (in Rs)'])>(Upper_bandp['annual premium (in Rs)']))])['annual premium (in Rs)']
In [54]:
customer_policy_details.loc[outlliers_amount.index,'annual premium (in Rs)']=customer_policy_details['annual premium (in Rs)'].mean()
 
Remove white spaces
In [55]:
customer_details['vehicle age']=customer_details['vehicle age'].str.strip()
In [56]:
customer_details['vehicle age']=customer_details['vehicle age'].str.replace(" ","")
In [57]:
customer_details['vehicle age']
Out[57]:
0         >2Years
1         1-2Year
2         >2Years
3          <1Year>2Years
381108    1-2Year
Name: vehicle age, Length: 380723, dtype: object
 
case correction(lower)
In [58]:
customer_details.columns=['customer_id','gender','age','driving licence present','region code','previously insured','vehicle age','vehicle damage']
In [59]:
def type_of(series):
    for value in series:
        if isinstance(value, str):
            return str


def chang_lower(df):
    for column in df.columns:
        col_type = type_of(df[column])
        if col_type == str:
            df[column] = df[column].str.lower()
    return df
In [60]:
chang_lower(customer_details)
Out[60]:
  customer_id gender age driving licence present region code previously insured vehicle age vehicle damage
0 1.0 male 44.0 1.0 28.0 0.0 >2years yes
1 2.0 male 76.0 1.0 3.0 0.0 1-2year no
2 3.0 male 47.0 1.0 28.0 0.0 >2years yes
3 4.0 male 21.0 1.0 11.0 1.0 <1year> no
4 5.0 female 29.0 1.0 41.0 1.0 <1year> no
... ... ... ... ... ... ... ... ...
381104 381105.0 male 74.0 1.0 26.0 1.0 1-2year no
381105 381106.0 male 30.0 1.0 37.0 1.0 <1year> no
381106 381107.0 male 21.0 1.0 30.0 1.0 <1year> no
381107 381108.0 female 68.0 1.0 14.0 0.0 >2years yes
381108 381109.0 male 46.0 1.0 29.0 0.0 1-2year no

380723 rows × 8 columns

In [61]:
chang_lower(customer_policy_details)
Out[61]:
  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

380722 rows × 5 columns

 
changing the data points into dummies as per needed
In [62]:
pd.get_dummies(customer_details,columns=['gender','vehicle age','vehicle damage'])
Out[62]:
  customer_id age driving licence present region code previously insured gender_female gender_male vehicle age_1-2year vehicle age_<1year> vehicle age_>2years vehicle damage_no vehicle damage_yes
0 1.0 44.0 1.0 28.0 0.0 0 1 0 0 1 0 1
1 2.0 76.0 1.0 3.0 0.0 0 1 1 0 0 1 0
2 3.0 47.0 1.0 28.0 0.0 0 1 0 0 1 0 1
3 4.0 21.0 1.0 11.0 1.0 0 1 0 1 0 1 0
4 5.0 29.0 1.0 41.0 1.0 1 0 0 1 0 1 0
... ... ... ... ... ... ... ... ... ... ... ... ...
381104 381105.0 74.0 1.0 26.0 1.0 0 1 1 0 0 1 0
381105 381106.0 30.0 1.0 37.0 1.0 0 1 0 1 0 1 0
381106 381107.0 21.0 1.0 30.0 1.0 0 1 0 1 0 1 0
381107 381108.0 68.0 1.0 14.0 0.0 1 0 0 0 1 0 1
381108 381109.0 46.0 1.0 29.0 0.0 0 1 1 0 0 1 0

380723 rows × 12 columns

 
Drop Duplicates (duplicated rows)
In [63]:
customer_details.drop_duplicates(inplace=True)
In [64]:
customer_policy_details.drop_duplicates(inplace=True)
 

Create a Master table for future use. Join the customer table and customer_policy table to get a master table using customer_id in both tables.

In [65]:
master_table=pd.merge(customer_details,customer_policy_details,on='customer_id')
master_table
Out[65]:
  customer_id gender age driving licence 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 >2years yes 40454.0 26.0 217.0 1.0
1 2.0 male 76.0 1.0 3.0 0.0 1-2year no 33536.0 26.0 183.0 0.0
2 3.0 male 47.0 1.0 28.0 0.0 >2years yes 38294.0 26.0 27.0 1.0
3 4.0 male 21.0 1.0 11.0 1.0 <1year> no 28619.0 152.0 203.0 0.0
4 5.0 female 29.0 1.0 41.0 1.0 <1year> no 27496.0 152.0 39.0 0.0
... ... ... ... ... ... ... ... ... ... ... ... ...
380331 381105.0 male 74.0 1.0 26.0 1.0 1-2year no 30170.0 26.0 88.0 0.0
380332 381106.0 male 30.0 1.0 37.0 1.0 <1year> no 40016.0 152.0 131.0 0.0
380333 381107.0 male 21.0 1.0 30.0 1.0 <1year> no 35118.0 160.0 161.0 0.0
380334 381108.0 female 68.0 1.0 14.0 0.0 >2years yes 44617.0 124.0 74.0 0.0
380335 381109.0 male 46.0 1.0 29.0 0.0 1-2year no 41777.0 26.0 237.0 0.0

380336 rows × 12 columns

 

Company needs some important information from the master table to make decisions for future growth.

 
i. Gender wise average annual premium
In [66]:
df1=master_table.groupby('gender')
df1['annual premium (in Rs)'].mean()
Out[66]:
gender
female    29273.474247
male      29323.099677
Name: annual premium (in Rs), dtype: float64
 
ii. Age wise average annual premium
In [67]:
df2=master_table.groupby('age')
df2['annual premium (in Rs)'].mean()
Out[67]:
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: 66, dtype: float64
 
iii. Is your data balanced between the genders?
In [68]:
df3=master_table.groupby('gender')['customer_id'].count()
df3
Out[68]:
gender
female    174485
male      205851
Name: customer_id, dtype: int64
In [69]:
# No. of male customer higer than female customer but ratio is approximately 1 so we can data is balanced as per gender.
 
iv. Vehicle age wise average annual premium.
In [70]:
df4=master_table.groupby('vehicle age')['annual premium (in Rs)'].mean()
df4
Out[70]:
vehicle age
1-2year    29102.009839
<1year>2years    32943.540830
Name: annual premium (in Rs), dtype: float64
 

any relation between Person Age and annual premium

In [71]:
correlation=master_table['age'].corr(master_table['annual premium (in Rs)'])

print('The correlation between age and annual premium is ',correlation)
 
The correlation between age and annual premium is  0.05065409799611512
In [72]:
# so the correlation between age and annual premium is between 0.5 and -0.5 , so there is no relation between these column
In [75]:
master_table.info()
 

Int64Index: 380336 entries, 0 to 380335
Data columns (total 12 columns):
 #   Column                   Non-Null Count   Dtype  
---  ------                   --------------   -----  
 0   customer_id              380336 non-null  float64
 1   gender                   380336 non-null  object 
 2   age                      380336 non-null  float64
 3   driving licence present  380336 non-null  float64
 4   region code              380336 non-null  float64
 5   previously insured       380336 non-null  float64
 6   vehicle age              380336 non-null  object 
 7   vehicle damage           380336 non-null  object 
 8   annual premium (in Rs)   380336 non-null  float64
 9   sales channel code       380336 non-null  float64
 10  vintage                  380336 non-null  float64
 11  response                 380336 non-null  float64
dtypes: float64(9), object(3)
memory usage: 37.7+ MB
In [76]:
customer_details.info()
 

Int64Index: 380723 entries, 0 to 381108
Data columns (total 8 columns):
 #   Column                   Non-Null Count   Dtype  
---  ------                   --------------   -----  
 0   customer_id              380723 non-null  float64
 1   gender                   380723 non-null  object 
 2   age                      380723 non-null  float64
 3   driving licence present  380723 non-null  float64
 4   region code              380723 non-null  float64
 5   previously insured       380723 non-null  float64
 6   vehicle age              380723 non-null  object 
 7   vehicle damage           380723 non-null  object 
dtypes: float64(5), object(3)
memory usage: 26.1+ MB
In [77]:
customer_policy_details.info()
 

Int64Index: 380722 entries, 0 to 381108
Data columns (total 5 columns):
 #   Column                  Non-Null Count   Dtype  
---  ------                  --------------   -----  
 0   customer_id             380722 non-null  float64
 1   annual premium (in Rs)  380722 non-null  float64
 2   sales channel code      380722 non-null  float64
 3   vintage                 380722 non-null  float64
 4   response                380722 non-null  float64
dtypes: float64(5)
memory usage: 17.4 MB
In [ ]:
 
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.