About

Berikut beberapa faktor yang mungkin bisa mempengaruhi biaya permi asuransi kesehatan:

age: Usia penerima manfaat.

sex: jenis kelamin female dan male.

bmi: Body mass index (kg / m ^ 2), menggunakan rasio tinggi dan berat idealnya 18.5 - 24.9.

children: Jumlah anak.

smoker: Merokok.

region: Daerah tempat tinggal northeast, southeast, southwest, northwest.

1. Preparation Data

1.1 Import Library

library(ggplot2)
library(dplyr)
library(Hmisc)
library(cowplot)
library(WVPlots)
library(tidyverse)
library(reshape2)
library(plotly)
library(data.table)
library(GGally)
library(tidymodels)
library(car)
library(scales)
library(lmtest)

1.2 Reading the file

df <- read.csv("insurances.csv")
head(df)
#>   age    sex    bmi children smoker    region   charges
#> 1  19 female 27.900        0    yes southwest 16884.924
#> 2  18   male 33.770        1     no southeast  1725.552
#> 3  28   male 33.000        3     no southeast  4449.462
#> 4  33   male 22.705        0     no northwest 21984.471
#> 5  32   male 28.880        0     no northwest  3866.855
#> 6  31 female 25.740        0     no southeast  3756.622

1.3 Handling Type Data

str(df)
#> 'data.frame':    1338 obs. of  7 variables:
#>  $ age     : int  19 18 28 33 32 31 46 37 37 60 ...
#>  $ sex     : chr  "female" "male" "male" "male" ...
#>  $ bmi     : num  27.9 33.8 33 22.7 28.9 ...
#>  $ children: int  0 1 3 0 0 0 1 3 2 0 ...
#>  $ smoker  : chr  "yes" "no" "no" "no" ...
#>  $ region  : chr  "southwest" "southeast" "southeast" "northwest" ...
#>  $ charges : num  16885 1726 4449 21984 3867 ...
df_raw <- df %>% 
  mutate(sex = factor(sex),
         smoker = factor(smoker),
         region = factor(region))
df <- df %>% 
  mutate(sex = factor(sex),
         smoker = factor(smoker),
         region = factor(region))
str(df_raw)
#> 'data.frame':    1338 obs. of  7 variables:
#>  $ age     : int  19 18 28 33 32 31 46 37 37 60 ...
#>  $ sex     : Factor w/ 2 levels "female","male": 1 2 2 2 2 1 1 1 2 1 ...
#>  $ bmi     : num  27.9 33.8 33 22.7 28.9 ...
#>  $ children: int  0 1 3 0 0 0 1 3 2 0 ...
#>  $ smoker  : Factor w/ 2 levels "no","yes": 2 1 1 1 1 1 1 1 1 1 ...
#>  $ region  : Factor w/ 4 levels "northeast","northwest",..: 4 3 3 2 2 3 3 2 1 2 ...
#>  $ charges : num  16885 1726 4449 21984 3867 ...

1.4 Describe Data

describe(df)
#> df 
#> 
#>  7  Variables      1338  Observations
#> --------------------------------------------------------------------------------
#> age 
#>        n  missing distinct     Info     Mean      Gmd      .05      .10 
#>     1338        0       47    0.999    39.21    16.21       18       19 
#>      .25      .50      .75      .90      .95 
#>       27       39       51       59       62 
#> 
#> lowest : 18 19 20 21 22, highest: 60 61 62 63 64
#> --------------------------------------------------------------------------------
#> sex 
#>        n  missing distinct 
#>     1338        0        2 
#>                         
#> Value      female   male
#> Frequency     662    676
#> Proportion  0.495  0.505
#> --------------------------------------------------------------------------------
#> bmi 
#>        n  missing distinct     Info     Mean      Gmd      .05      .10 
#>     1338        0      548        1    30.66    6.893    21.26    22.99 
#>      .25      .50      .75      .90      .95 
#>    26.30    30.40    34.69    38.62    41.11 
#> 
#> lowest : 15.960 16.815 17.195 17.290 17.385, highest: 48.070 49.060 50.380 52.580 53.130
#> --------------------------------------------------------------------------------
#> children 
#>        n  missing distinct     Info     Mean      Gmd 
#>     1338        0        6    0.899    1.095    1.275 
#> 
#> lowest : 0 1 2 3 4, highest: 1 2 3 4 5
#>                                               
#> Value          0     1     2     3     4     5
#> Frequency    574   324   240   157    25    18
#> Proportion 0.429 0.242 0.179 0.117 0.019 0.013
#> --------------------------------------------------------------------------------
#> smoker 
#>        n  missing distinct 
#>     1338        0        2 
#>                       
#> Value         no   yes
#> Frequency   1064   274
#> Proportion 0.795 0.205
#> --------------------------------------------------------------------------------
#> region 
#>        n  missing distinct 
#>     1338        0        4 
#>                                                   
#> Value      northeast northwest southeast southwest
#> Frequency        324       325       364       325
#> Proportion     0.242     0.243     0.272     0.243
#> --------------------------------------------------------------------------------
#> charges 
#>        n  missing distinct     Info     Mean      Gmd      .05      .10 
#>     1338        0     1337        1    13270    12301     1758     2347 
#>      .25      .50      .75      .90      .95 
#>     4740     9382    16640    34832    41182 
#> 
#> lowest :  1121.874  1131.507  1135.941  1136.399  1137.011
#> highest: 55135.402 58571.074 60021.399 62592.873 63770.428
#> --------------------------------------------------------------------------------

#Insight:

Age: rata-rata usia adalah 39.21 dengan rentang usia dari 18 hingga 64 tahun.

Sex: terdapat 662 perempuan dan 676 laki-laki dalam sampel tersebut.

BMI: rata-rata bmi adalah 30.66 dan rentangnya berkisar dari 15.96 hingga 53.13.

Children: rata-rata jumlah anak adalah 1.095 dan rentangnya adalah dari 0 hingga 5 anak.

Smoke: terdapat 1064 orang yang tidak merokok dan 274 orang yang merokok dalam sampel tersebut.

Region: terdapat 4 wilayah yaitu northeast, northwest, southeast, dan southwest dengan frekuensi yang hampir sama.

Charges: rata-rata biaya adalah 13270 dengan rentang biaya dari 1121.87 hingga 63770.43

1.5 Handling Missing Value

colSums(is.na(df))
#>      age      sex      bmi children   smoker   region  charges 
#>        0        0        0        0        0        0        0

2. EDA

2.1 Distribution Data

p <- ggplot(df, aes(x = charges)) +
  geom_histogram(aes(y=..density..), bins=30, color = "black", fill = "cyan") +
  geom_density(color="blue", size=1) +
  ggtitle("Distribution of Charges") +
  theme_classic() +
  xlab("Charges") +
  ylab("Density")

ggplotly(p)

Distribusi right-skewed, Untuk membuatnya lebih mendekati normal dapat menggunakan skala logaritmik.

library(ggplot2)

q<-ggplot(df, aes(x = log10(charges))) +
  geom_density(color = "red", fill = "pink", alpha = 0.5) +
  ggtitle("Distribution of Charges (log10 scale)") +
  xlab("Log10 of Charges") +
  ylab("Density")

ggplotly(q)

2.2 Total Charges by Region

charges <- df %>%
  group_by(region) %>%
  summarise(total_charges = sum(charges))  %>% 
  arrange(desc(total_charges))

ChargesRegion<-ggplot(charges, aes(x = total_charges, y = reorder(region, total_charges))) +
  geom_bar(stat = "identity", aes(fill = total_charges)) +
  scale_fill_gradient(low = "lightblue", high = "darkblue") +
  ggtitle("Total Charges by Region (descending order)") +
  xlab("Total Charges") +
  ylab("Region")

ggplotly(ChargesRegion)

#Inight:

Secara keseluruhan, biaya medis tertinggi berada di Southeast dan yang terendah berada di Wilayah southwest.

2.3 Charges by Region and Sex

RegionSx<-ggplot(df, aes(x = region, y = charges, fill = sex)) +
  geom_bar(stat = "identity", position = "dodge") +
  scale_fill_manual(values = c("#4BACC6", "#ED7D31")) +
  ggtitle("Charges by Region and Sex") +
  xlab("Region") +
  ylab("Charges")
ggplotly(RegionSx)

#Inight:

Dari seluruh region southeast mendapatkan charges tertinggi dengan perempuan sebagai chrages tertinggi.

2.4 Charges by Region and Smoking Status

RegionSmoking <-ggplot(df, aes(x = region, y = charges, fill = smoker)) +
  geom_col(position = "dodge") +
  scale_fill_manual(values = c("#FEE0D2", "#FB6A4A")) +
  ggtitle("Charges by Region and Smoking Status") +
  xlab("Region") +
  ylab("Charges")
ggplotly(RegionSmoking)

#Inight:

Dari seluruh region southeast merupakan prokok terbanyak.

2.5 Charges by Region and Number of Children

RegionCharger<-ggplot(df, aes(x = region, y = charges, fill = factor(children))) +
  geom_col(position = "dodge") +
  scale_fill_discrete(name = "Children") +
  ggtitle("Charges by Region and Number of Children") +
  xlab("Region") +
  ylab("Charges")
ggplotly(RegionCharger)

#Inight:

Seperti yang dapat dilihat dari grafik diatas, biaya medis tertinggi akibat merokok masih terdapat di wilayah Southeast, namun yang terendah ada di wilayah Northeast. Orang-orang di wilayah Southwest umumnya merokok lebih banyak daripada orang-orang di wilayah Northeast, tetapi orang-orang di wilayah Northeast memiliki biaya yang lebih tinggi berdasarkan jenis kelamin dibandingkan di wilayah Southwest dan Northwest secara keseluruhan. Dan orang-orang yang memiliki anak cenderung memiliki biaya medis yang lebih tinggi secara keseluruhan.

2.6 The comparison between charges and age, BMI, and children.

par(mfrow=c(1,3))

ChargesAge<- ggplot(df, aes(x = age, y = charges, color = smoker)) +
  geom_point() +
  geom_smooth(method = 'lm', se = FALSE) +
  labs(title = 'Age vs Charges')

ChargesBmi<-ggplot(df, aes(x = bmi, y = charges, color = smoker)) +
  geom_point() +
  geom_smooth(method = 'lm', se = FALSE) +
  labs(title = 'BMI vs Charges')

ChargesChild<-ggplot(df, aes(x = children, y = charges, color = smoker)) +
  geom_point() +
  geom_smooth(method = 'lm', se = FALSE) +
  labs(title = 'Children vs Charges')
ggplotly(ChargesAge)
ggplotly(ChargesBmi)
ggplotly(ChargesChild)

#Inight:

Merokok memiliki dampak terbesar pada biaya medis, meskipun biaya tersebut meningkat dengan bertambahnya usia, bmi, dan jumlah anak. Selain itu, orang yang memiliki anak cenderung merokok lebih sedikit.

2.7 Correlation

df <- df %>%
mutate(across(c(sex, smoker, region), as.factor),
sex = as.numeric(sex) - 1,
smoker = as.numeric(smoker) - 1)

df$sex <- as.numeric(df$sex)
df$smoker <- as.numeric(df$smoker)
df$region <- as.numeric(df$region)

ggplotly(ggcorr(df, label=TRUE))

#Inight:

Dari grafik diatas perokok memiliki korelasi tertinggi terhadap biaya.

4. Pretrain and Splitting

n_train <- round(0.8 * nrow(df_raw))
train_indices <- sample(1:nrow(df_raw), n_train)
Data_train <- df_raw[train_indices, ]
Data_test <- df_raw[-train_indices, ]

formula_split <- as.formula("charges ~ age + sex + bmi + children + smoker + region")

5. Train Test

5.1 Summary Model All

#model
model_all <- lm(formula_split, data = Data_train)
summary(model_all)
#> 
#> Call:
#> lm(formula = formula_split, data = Data_train)
#> 
#> Residuals:
#>    Min     1Q Median     3Q    Max 
#> -10471  -3026  -1055   1315  24191 
#> 
#> Coefficients:
#>                   Estimate Std. Error t value            Pr(>|t|)    
#> (Intercept)     -12221.038   1101.191 -11.098 <0.0000000000000002 ***
#> age                252.578     13.115  19.258 <0.0000000000000002 ***
#> sexmale              1.294    370.679   0.003              0.9972    
#> bmi                354.072     31.922  11.092 <0.0000000000000002 ***
#> children           484.077    153.876   3.146              0.0017 ** 
#> smokeryes        23398.297    464.717  50.350 <0.0000000000000002 ***
#> regionnorthwest   -221.464    531.814  -0.416              0.6772    
#> regionsoutheast  -1168.132    533.854  -2.188              0.0289 *  
#> regionsouthwest   -802.282    533.315  -1.504              0.1328    
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> Residual standard error: 6048 on 1061 degrees of freedom
#> Multiple R-squared:  0.7475, Adjusted R-squared:  0.7456 
#> F-statistic: 392.6 on 8 and 1061 DF,  p-value: < 0.00000000000000022

#Inight:

Seperti yang dapat kita lihat, ringkasan dari sebuah model menunjukkan bahwa beberapa variabel tidak signifikan yaitu sex, sementara merokok sepertinya memiliki pengaruh besar pada biaya medis. Melatih model tanpa variabel yang tidak signifikan dan memeriksa apakah kinerjanya dapat ditingkatkan.

5.2 Save Model

#save model r sqr
r_sqr_model1 <- summary(model_all)$r.squared
#save model prediction
predict_model1 <- predict(model_all, Data_test)
#save model residual
residual_model1 <- Data_test$charges - predict_model1
#save model rmse
rmse_model1 <- sqrt(mean(residual_model1^2))

5.1 Summary Model Correlation

formula_2 <- as.formula("charges ~ age+bmi+children+smoker+region")
model_2 <- lm(formula_2, data= Data_train)
summary(model_2)
#> 
#> Call:
#> lm(formula = formula_2, data = Data_train)
#> 
#> Residuals:
#>    Min     1Q Median     3Q    Max 
#> -10470  -3026  -1055   1316  24191 
#> 
#> Coefficients:
#>                  Estimate Std. Error t value             Pr(>|t|)    
#> (Intercept)     -12220.56    1092.18 -11.189 < 0.0000000000000002 ***
#> age                252.58      13.11  19.268 < 0.0000000000000002 ***
#> bmi                354.08      31.86  11.112 < 0.0000000000000002 ***
#> children           484.09     153.78   3.148              0.00169 ** 
#> smokeryes        23398.35     464.20  50.406 < 0.0000000000000002 ***
#> regionnorthwest   -221.48     531.54  -0.417              0.67699    
#> regionsoutheast  -1168.14     533.60  -2.189              0.02880 *  
#> regionsouthwest   -802.29     533.06  -1.505              0.13260    
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> Residual standard error: 6045 on 1062 degrees of freedom
#> Multiple R-squared:  0.7475, Adjusted R-squared:  0.7458 
#> F-statistic: 449.1 on 7 and 1062 DF,  p-value: < 0.00000000000000022

#Inight:

Di kedua model, merokok memiliki koefisien positif yang sangat signifikan, menunjukkan bahwa perokok cenderung memiliki biaya medis yang jauh lebih tinggi dibandingkan dengan non-perokok. Usia, BMI, dan memiliki anak juga memiliki koefisien positif yang signifikan, artinya jika variabel-variabel ini meningkat, biaya medis juga akan meningkat.

Variabel region memiliki koefisien yang kurang signifikan, hanya region 3 dan region 4 yang memiliki nilai p mendekati 0,05, menunjukkan hubungan yang lemah dengan biaya medis.

Nilai R-kuadrat yang disesuaikan untuk kedua model sekitar 0,76, menunjukkan bahwa model-model tersebut menjelaskan sekitar 76% variansi pada data. Residual standard error merepresentasikan jumlah variasi rata-rata pada variabel respons yang tidak dijelaskan oleh model. Kedua model memiliki nilai-nilai yang sangat mirip untuk metrik-metrik ini, menunjukkan bahwa mereka dapat dibandingkan dari segi performa.

6. Model Performance

6.1 Grafik Model Performance

Data_test$prediction <- predict(model_2, Data_test)
ggplotly(ggplot(Data_test, aes(x = prediction, y = charges)) + 
  geom_point(color = "green", alpha = 0.7) + 
  geom_abline(color = "red") +
  ggtitle("Prediction vs. Real values"))
Data_test$residuals<- Data_test$charges - Data_test$prediction
ggplotly(ggplot(data = Data_test, aes(x = prediction, y = residuals)) +
  geom_pointrange(aes(ymin = 0, ymax = residuals), color = "yellow", alpha = 0.7) +
  geom_hline(yintercept = 0, linetype = 3, color = "red") +
  ggtitle("Residuals vs. Linear model prediction"))
ggplotly(ggplot(Data_test, aes(x = residuals)) + 
  geom_histogram(bins = 15, fill = "red") +
  ggtitle("Histogram of residuals"))
ggplotly(GainCurvePlot(Data_test, "prediction", "charges", "Model"))

#Inight:

Dari grafik diatas model menunjukan error mendekati 0, jadi model sudah baik.

6.2 An example of using the model

  1. Monkey D luffy: 17 years old, BMI 32, has no children, smokes, from northenwest region.
Luffy <- data.frame(age= 55,
                    bmi= 40,
                    children= 0,
                    sex="male",
                    smoker="yes",
                    region="southeast")
predict(model_all, Luffy)
#>        1 
#> 38065.09