Descriptive Statistics
Univariate Statistics
Data
In our example this week, we are going to use the fake data - about real estates in Wroclaw - prices by districts, size of apartments and many more.
Preprocessing
As you can see, not all formats of our variables are adapted. We need to prepare appropriate formats of our variables according to their measurement scale and future application.
Frequency Tables
In the first step of our analysis, we will group our data into a simple frequency table.
First, let’s look at the distribution of housing prices in our sample and verify tabular validity using the TAI measure:
Ok, it looks quite ugly, so let’s wrap it up using the ‘kable’ package:
|
## # classes Goodness of fit Tabular accuracy
## 10.0000000 0.9780872 0.8508467
As we can see - the TAI index is quite high. 0.85 means that we can accept the proposed construction of the frequency table.
Basic plots
In this section, we should represent our data using basic (pre-installed in R) graphics. Select the most appropriate graphs depending on the scale of the selected variables. Explore the heterogeneity of the distribution by presenting the data by group (e.g., by neighborhood, building type, etc.). Don’t forget about main titles, labels and legends. Read more about graphical parameters here.
Note that the echo = FALSE parameter has been added to
the code snippet to prevent printing the R code that generated the
graph.
ggplot2 plots
Now, let’s use the ggplot2 and ggpubr libraries to plot.
Ggplot2 allows you to show the average value for each group using the stat_summary() function. You no longer need to calculate average values before creating a graph!
RainCloud Plot
Faceting
Faceting generates small multiples, each showing a different subset of the data. They are a powerful tool for exploratory data analysis: you can quickly compare patterns in different parts of the data and see if they are the same or different. Read more here.
Univariate Statistics
Before automatically reporting the full summary table of descriptive statistics, this time your goal is to measure the central tendency of the price distribution. Compare the mean, median, and mode along with positional measures - quantiles - by district and building type or number of rooms in the apartment.
## [1] 760035
## [1] 755719.5
## [1] 186099.8
## [1] 34633125960
## [1] 0.2448568
## 75%
## 282686.5
sx<-IQR(price_PLN)/2 #interquartile deviation
coeff_varx<-sx/median(price_PLN) #IQR coefficient of variability %
coeff_varx## 75%
## 0.1870314
## [1] 359769
## [1] 1277691
## 0% 10% 25% 50% 75% 95% 100%
## 359769.0 518806.8 619073.8 755719.5 901760.2 1054250.8 1277691.0
Ok, we have calculated all of the basic summary statistics above. Let’s wrap them up together now.
| rooms | boxplot | histogram | line1 | line2 | points1 |
|---|---|---|---|---|---|
| 1 | |||||
| 2 | |||||
| 3 | |||||
| 4 |
Summary tables
Ok, now we will finally summarize the basic measures of central tendency for prices by district/building type using the ‘kable’ package. Feel free to customize your final report. See some hints here.
| variables | 1 room | 2 rooms | 3 rooms | 4 rooms |
|---|---|---|---|---|
| Price in PLN | | | | |
| Min | 359769 | 590286 | 632770 | 736669 |
| Max | 657146 | 888634 | 965829 | 1277691 |
| Q1 | 479684.75 | 634757.25 | 769683.75 | 909371.5 |
| Median | 520507 | 677260 | 846303.5 | 964338.5 |
| Q3 | 555024.75 | 717728.5 | 901078.75 | 1050976.75 |
| Mean | 515518.05 | 683567.7 | 833706.02 | 974809.96 |
| Sd | 66951.03 | 65072.66 | 86943.9 | 113819.21 |
| IQR | 75340 | 82971.25 | 131395 | 141605.25 |
| Sx | 37670 | 41485.62 | 65697.5 | 70802.62 |
| Var % | 0.13 | 0.1 | 0.1 | 0.12 |
| IQR Var % | 0.14 | 0.12 | 0.16 | 0.15 |
| Skewness | -0.2 | 0.8 | -0.42 | 0.33 |
| Kurtosis | -0.38 | 0.48 | -0.83 | 0.05 |
gtsummary
We can calculate easily descriptive statistics also using gtsummary package:
apartments %>%
select(price_PLN,rooms) %>%
tbl_summary(label= price_PLN ~ "Price",digits=c(price_PLN)~2,by=rooms,type = all_continuous() ~ "continuous2", statistic = all_continuous() ~ c("{N_nonmiss}", "{median} ({p25}, {p75})", "{min}, {max}"),missing = "no")| Characteristic | 1, N = 44 | 2, N = 50 | 3, N = 58 | 4, N = 48 |
|---|---|---|---|---|
| Price | ||||
| N | 44.00 | 50.00 | 58.00 | 48.00 |
| Median (IQR) | 520,507.00 (479,684.75, 555,024.75) | 677,260.00 (634,757.25, 717,728.50) | 846,303.50 (769,683.75, 901,078.75) | 964,338.50 (909,371.50, 1,050,976.75) |
| Range | 359,769.00, 657,146.00 | 590,286.00, 888,634.00 | 632,770.00, 965,829.00 | 736,669.00, 1,277,691.00 |
dfSummary
dfSummary() creates a summary table with statistics, frequencies and graphs for all variables in a data frame. The information displayed is type-specific (character, factor, numeric, date) and also varies according to the number of distinct values.
When using dfSummary() in R Markdown documents, it is generally a good idea to exclude a column or two to avoid margin overflow. Since the Valid and Missing columns are redundant, we can drop either one of them.
dfSummary(apartments,
plain.ascii = FALSE,
style = "grid",
graph.magnif = 0.75,
valid.col = FALSE,
tmp.img.dir = "/tmp")## temporary images written to 'C:\tmp'
Data Frame Summary
apartments
Dimensions: 200 x 6
Duplicates: 0
| No | Variable | Stats / Values | Freqs (% of Valid) | Graph | Missing |
|---|---|---|---|---|---|
| 1 | price_PLN [numeric] |
Mean (sd) : 760035 (186099.8) min < med < max: 359769 < 755719.5 < 1277691 IQR (CV) : 282686.5 (0.2) |
200 distinct values | 0 (0.0%) |
|
| 2 | price_EUR [numeric] |
Mean (sd) : 175934 (43078.6) min < med < max: 83280 < 174935 < 295762 IQR (CV) : 65436.2 (0.2) |
200 distinct values | 0 (0.0%) |
|
| 3 | rooms [ordered, factor] |
1. 1 2. 2 3. 3 4. 4 |
44 (22.0%) 50 (25.0%) 58 (29.0%) 48 (24.0%) |
0 (0.0%) |
|
| 4 | size [numeric] |
Mean (sd) : 46.2 (20.1) min < med < max: 17 < 43.7 < 87.7 IQR (CV) : 30.2 (0.4) |
162 distinct values | 0 (0.0%) |
|
| 5 | district [factor] |
1. Biskupin 2. Krzyki 3. Srodmiescie |
65 (32.5%) 79 (39.5%) 56 (28.0%) |
0 (0.0%) |
|
| 6 | building_type [factor] |
1. kamienica 2. niski blok 3. wiezowiec |
61 (30.5%) 63 (31.5%) 76 (38.0%) |
0 (0.0%) |
To produce optimal results, summarytools has its own version of the base by() function. It’s called stby(), and we use it exactly as we would by():
(stats_by_rooms <- stby(data = apartments, INDICES = apartments$rooms, FUN = descr, stats = "common", transpose = TRUE))## Non-numerical variable(s) ignored: rooms, district, building_type
Descriptive Statistics
apartments
Group: rooms = 1
N: 44
| Mean | Std.Dev | Min | Median | Max | N.Valid | Pct.Valid | |
|---|---|---|---|---|---|---|---|
| price_EUR | 119332.95 | 15497.90 | 83280.00 | 120488.00 | 152117.00 | 44.00 | 100.00 |
| price_PLN | 515518.05 | 66951.03 | 359769.00 | 520507.00 | 657146.00 | 44.00 | 100.00 |
| size | 19.28 | 1.46 | 17.00 | 19.10 | 21.90 | 44.00 | 100.00 |
Group: rooms = 2
N: 50
| Mean | Std.Dev | Min | Median | Max | N.Valid | Pct.Valid | |
|---|---|---|---|---|---|---|---|
| price_EUR | 158233.22 | 15063.13 | 136640.00 | 156773.00 | 205702.00 | 50.00 | 100.00 |
| price_PLN | 683567.70 | 65072.66 | 590286.00 | 677260.00 | 888634.00 | 50.00 | 100.00 |
| size | 36.80 | 4.46 | 29.60 | 35.95 | 43.70 | 50.00 | 100.00 |
Group: rooms = 3
N: 58
| Mean | Std.Dev | Min | Median | Max | N.Valid | Pct.Valid | |
|---|---|---|---|---|---|---|---|
| price_EUR | 192987.55 | 20125.88 | 146475.00 | 195904.00 | 223572.00 | 58.00 | 100.00 |
| price_PLN | 833706.02 | 86943.90 | 632770.00 | 846303.50 | 965829.00 | 58.00 | 100.00 |
| size | 53.33 | 7.21 | 41.20 | 53.45 | 65.20 | 58.00 | 100.00 |
Group: rooms = 4
N: 48
| Mean | Std.Dev | Min | Median | Max | N.Valid | Pct.Valid | |
|---|---|---|---|---|---|---|---|
| price_EUR | 225650.42 | 26347.03 | 170525.00 | 223226.50 | 295762.00 | 48.00 | 100.00 |
| price_PLN | 974809.96 | 113819.21 | 736669.00 | 964338.50 | 1277691.00 | 48.00 | 100.00 |
| size | 72.05 | 10.18 | 53.30 | 70.85 | 87.70 | 48.00 | 100.00 |
Tidy Tables
When generating freq() or descr() tables, it is possible to turn the results into “tidy” tables with the use of the tb() function (think of tb as a diminutive for tibble). For example:
## # A tibble: 3 × 8
## variable mean sd min med max n.valid pct.valid
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 price_EUR 175934. 43079. 83280 174935 295762 200 100
## 2 price_PLN 760035. 186100. 359769 755720. 1277691 200 100
## 3 size 46.2 20.1 17 43.7 87.7 200 100
Here are some examples showing how lists created using stby() or group_by() can be transformed into tidy tibbles.
grouped_descr <- stby(data = apartments,INDICES = apartments$rooms, FUN = descr, stats = "common")
grouped_descr %>% tb()## # A tibble: 12 × 9
## rooms variable mean sd min med max n.valid pct.valid
## <fct> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 price_EUR 119333. 15498. 83280 120488 1.52e5 44 100
## 2 1 price_PLN 515518. 66951. 359769 520507 6.57e5 44 100
## 3 1 size 19.3 1.46 17 19.1 2.19e1 44 100
## 4 2 price_EUR 158233. 15063. 136640 156773 2.06e5 50 100
## 5 2 price_PLN 683568. 65073. 590286 677260 8.89e5 50 100
## 6 2 size 36.8 4.46 29.6 36.0 4.37e1 50 100
## 7 3 price_EUR 192988. 20126. 146475 195904 2.24e5 58 100
## 8 3 price_PLN 833706. 86944. 632770 846304. 9.66e5 58 100
## 9 3 size 53.3 7.21 41.2 53.4 6.52e1 58 100
## 10 4 price_EUR 225650. 26347. 170525 223226. 2.96e5 48 100
## 11 4 price_PLN 974810. 113819. 736669 964338. 1.28e6 48 100
## 12 4 size 72.0 10.2 53.3 70.8 8.77e1 48 100
A Bridge to Other Packages
stby(data = apartments,
INDICES = apartments$rooms,
FUN = descr,
stats = "fivenum") %>%
tb(order = 3) %>%
kable(format = "html", digits = 2) %>%
collapse_rows(columns = 1, valign = "top")| variable | rooms | min | q1 | med | q3 | max |
|---|---|---|---|---|---|---|
| price_EUR | 1 | 83280.0 | 110881.0 | 120488.00 | 128568.00 | 152117.0 |
| 2 | 136640.0 | 146754.0 | 156773.00 | 166259.00 | 205702.0 | |
| 3 | 146475.0 | 177478.0 | 195904.00 | 208599.00 | 223572.0 | |
| 4 | 170525.0 | 209827.5 | 223226.50 | 243300.00 | 295762.0 | |
| price_PLN | 1 | 359769.0 | 479005.5 | 520507.00 | 555411.50 | 657146.0 |
| 2 | 590286.0 | 633978.0 | 677260.00 | 718237.00 | 888634.0 | |
| 3 | 632770.0 | 766707.0 | 846303.50 | 901149.00 | 965829.0 | |
| 4 | 736669.0 | 906455.0 | 964338.50 | 1051055.50 | 1277691.0 | |
| size | 1 | 17.0 | 18.1 | 19.10 | 20.60 | 21.9 |
| 2 | 29.6 | 32.9 | 35.95 | 40.50 | 43.7 | |
| 3 | 41.2 | 47.9 | 53.45 | 59.70 | 65.2 | |
| 4 | 53.3 | 64.2 | 70.85 | 82.15 | 87.7 |
Your turn!
Your task this week is to: prepare your own descriptive analysis for the “CreditCard” dataset (AER package). It is a cross-sectional dataframe on the credit history for a sample of applicants for a type of credit card.
Are the yearly incomes (in USD 10,000), credit card expenditures, age, ratio of monthly credit card expenditure to yearly income - significantly different for applicants for customers with different credit risk (“card” variable - factor)?
Prepare a professional data visualizations, descriptive statistics’ tables and interpret them.
data(CreditCard)
#there are some applicants that are younger that one year old, so we assume some mistake in that matter:
CreditCard<- CreditCard[CreditCard$age > 18, ]Accepted <- CreditCard[CreditCard$card == 'yes', ]
NotAccepted <- CreditCard[CreditCard$card == 'no', ]
nrow(Accepted)## [1] 1017
## [1] 295
## [1] 0.7751524
We can see that >77% of Applications got accepted.
Now lets look at some basic graphs showing relation of other variables and applications for credit card being accepted.
CreditCard %>%
filter(card %in% c('no','yes')) %>%
ggplot(aes(x = factor(card), y = age, fill = factor(card))) +
stat_halfeye(
adjust = 0.5,
justification = -0.2,
.width = 0,
point_colour = NA
) +
geom_boxplot(
width = 0.12,
outlier.color = NA,
alpha = 0.5
) +
stat_dots(
side = "left",
justification = 1.1,
binwidth = 0.05
) +
labs(
title = "Age in regards to credit card application acceptance",
x = "accepted",
y = "Age",
fill = "Got accepted fo credit card"
) +
coord_flip()
Age is visibly positive-skewed for both groups and range of age of
accepted applicants is bigger. There is no visible significant dominance
of acceptance of applications in any age group, accepted applicators
could tend to be slightly older, which we will look into later.
CreditCard$income<- CreditCard$income
CreditCard %>%
filter(card %in% c('no','yes')) %>%
ggplot(aes(x = factor(card), y = income, fill = factor(card))) +
stat_halfeye(
adjust = 0.5,
justification = -0.2,
.width = 0,
point_colour = NA
) +
geom_boxplot(
width = 0.15,
outlier.color = NA,
alpha = 0.5
) +
stat_dots(
side = "left",
justification = 1.1,
binwidth = 0.0025
) +
labs(
title = "Income in regards to credit card application acceptance",
x = "accepted",
y = "Income [in 10.000 USD]",
fill = "Got accepted fo credit card"
) +
coord_flip()
We can notice income being positive-skewed and leptokurtic for both
groups. Range is bigger for accepted applicants. Income seems to be
lower for not accepted applicants and will be analysed further
later.
library(ggplot2)
hist(NotAccepted$reports, col=rgb(0,0,1,0.3), xlim=c(0, max(NotAccepted$reports)),
xlab='reports', ylab='declined applications', main='Major derogatory reports for not accepted Applicants')hist(Accepted$reports, col=rgb(1,0,1,0.3), xlim=c(0, max(Accepted$reports)),
xlab='reports', ylab='accepted applications', main='Major derogatory reports for accepted Applicants')No applicant with more than 4 reports got accepted, overall not accepted applicants tend to have more derogatory reports. With bigger number of reports percentile of rejected applications also rises and we can see that having reports significantly affects and decreases chances of being accepted, although having reports is not the case with majority of applicants.
## [1] 0.01054498
hist(Accepted$active, col=rgb(1,1,0.5,1), xlim=c(0, max(NotAccepted$active)),
xlab='active credit accounts', ylab='applications', main='Number of active credit accounts for applicants')
hist(NotAccepted$active, col=rgb(0,1,0,1), xlim=c(0, max(NotAccepted$active)), add = TRUE)
legend('topright', c('accepted', 'not accepted'),
fill=c(rgb(1,1,0.5,1), rgb(0,1,0,1)))We can see, that with bigger number of credit accounts comes bigger share of accepted applications. It is probably due to the fact that opening credit accounts have somewhat similar requirements - applicants with many accounts could be able to meet those requirements easier.
CreditCard %>%
filter(card %in% c('no','yes')) %>%
ggplot(aes(x = factor(card), y = months, fill = factor(card))) +
stat_halfeye(
adjust = 0.5,
justification = -0.3,
.width = 0,
point_colour = NA
) +
geom_boxplot(
width = 0.15,
outlier.color = NA,
alpha = 0.5
) +
stat_dots(
side = "left",
justification = 1.1,
binwidth = 0.1
) +
labs(
title = "Months lived at current address in regards to application acceptance",
x = "accepted",
y = "months",
fill = "Got accepted fo credit card"
) +
coord_flip()hist(Accepted$months, col=rgb(1,0,0,0.8), xlim=c(0, 300),
xlab='months', ylab='applications', main="Months lived at current address in regards to application acceptance")
hist(NotAccepted$months, col=rgb(0,0,1,0.8), xlim=c(0, 300), add = TRUE)
legend('topright', c('accepted', 'not accepted'),
fill=c(rgb(1,0,0,0.8), rgb(0,0,1,0.8)))Although people who lived at current address for long time, meaning more than 8 years, tend to be accepted for credit card application, the biggest group of applicants have not been living under their current address for longer time than 4-5 years. For this group months living at current address do not seem to affect decision about application too much, as applicants from this group were not more or less accepted than applicants overall, not regarding how long they lived at their current address. With smaller group mentioned, accepted applicants tend to have lived longer at their address.
hist(Accepted$dependents, col=rgb(1,0,0.5,1), xlim=c(0, max(Accepted$dependents)),
xlab='number of dependants', ylab='applications', main='Number of dependants for applicants')
hist(NotAccepted$dependents, col=rgb(0.7,1,0,1), xlim=c(0, max(Accepted$dependents)), add = TRUE)
legend('topright', c('accepted', 'not accepted'),
fill=c(rgb(1,0,0.5,1), rgb(0.7,1,0,1)))We can see, that share of declined applications tends to be bigger with bigger number of dependants.
## [1] 528
## [1] 489
## [1] 205
## [1] 90
Share of applicants that do not own their home is significantly bigger in group of applicants that were not accepted.
Just to check if no applicant has more than one major card:
## [1] 1
## [1] 854
## [1] 163
## [1] 219
## [1] 76
Share of applicants that do own major credit card is bigger in group of applicants that were accepted.
## [1] 954
## [1] 63
## [1] 267
## [1] 28
Share of applicants that are self-employed is bigger in group of applicants that were not accepted.
## [1] 0.08840693
## [1] 0.0004770558
## [1] 0.0598016
## [1] 0.0004651163
We can predict and see above, that share is significantly lower for not accepted applicants, as it depends strongly on being accepted. the same comes for expenditure, that is just equal to zero for all rejected applicants:
## [1] 0
## [1] 238.6245
Now, let’s take a look on univariate statistics for whole group of applicants, accepted ones and those who weren’t accepted:
Arithmetic mean:
## [1] 3.367257
## [1] 3.453847
## [1] 3.068741
Average income is visibly lower for not accepted applicants, which could suggest that income could affect decision of acceptance, if it is not affected by outliners in misguiding way.
Median
## [1] 2.9
## [1] 3
## [1] 2.58
Median, not being affected by extreme values as mean, also puts central tendency of income for group of accepted applicants higher then for group of not accepted applicants. For every group mean is remarkably bigger than median, so, as noticed earlier, shape of distribution for income of each group of applicants is right-skewed.
Standard deviation
## [1] 1.697377
## [1] 1.710739
## [1] 1.618076
Standard deviation do not differ much between groups. Being relatively high, it suggests data being more widely scattered around the mean.
Variance
## [1] 2.881089
## [1] 2.926627
## [1] 2.618171
Analogically, we can conclude the same as from standard deviation. We can see more clearly than above that variance is bigger for accepted applicants.
Coefficient of variation in %
## [1] 50.40831
## [1] 49.5314
## [1] 52.72769
group of not accepted applicants is slightly more variable relative to their income than accepted applicants, but it is not a markable difference.
Quantiles
## 0% 10% 25% 50% 75% 95% 100%
## 0.210000 1.800000 2.237125 2.900000 4.000000 6.900000 13.500000
## 0% 10% 25% 50% 75% 95% 100%
## 0.21 1.90 2.35 3.00 4.00 7.00 13.50
## 0% 10% 25% 50% 75% 95% 100%
## 0.4900 1.6752 2.0000 2.5800 3.6500 6.1500 11.0000
Difference between quartiles = Q3-Q1
## 75%
## 1.762875
## 75%
## 1.65
## 75%
## 1.65
Difference between quartiles is the same for both groups of accepted and not accepted applicants.
IQR coefficient of variation in %
#interquartile deviation
sx<-IQR(CreditCard$income)/2
sxA<-IQR(Accepted$income)/2
sxNA<-IQR(NotAccepted$income)/2
coeff_varx<- 100 * sx/median(CreditCard$income)
coeff_varx## 75%
## 30.3944
## 75%
## 27.5
## 75%
## 31.97674
Interquartile coefficient of variation is, similarly to coefficient of variation counted in regards to whole group, bigger for not accepted applicants, with bigger difference between coefficient for accepted and not accepted group. The level of dispersion around the mean in interquartile would be higher for not accepted applicants.
Minimum and maximum
## [1] 0.21
## [1] 0.49
## [1] 13.5
## [1] 11
Let’s also see income of accepted and not accepted applicants on graphs:
list <- split(CreditCard$income, CreditCard$card)
inline_plot <- data.frame(card = c('no', 'yes'), boxplot = "", histogram = "",
line1 = "", line2 = "", points1 = "")
inline_plot %>%
kbl(booktabs = TRUE) %>%
kable_paper(full_width = FALSE) %>%
column_spec(2, image = spec_boxplot(list)) %>%
column_spec(3, image = spec_hist(list)) %>%
column_spec(4, image = spec_plot(list, same_lim = TRUE)) %>%
column_spec(5, image = spec_plot(list, same_lim = FALSE)) %>%
column_spec(6, image = spec_plot(list, type = "p"))| card | boxplot | histogram | line1 | line2 | points1 |
|---|---|---|---|---|---|
| no | |||||
| yes |
To summarize above statistics regarding income, we can see that level of income significantly differs between groups of accepted and not accepted applicants, as it tends to be lower for applicants that were not accepted for credit card.
CreditCard$income<- CreditCard$income * 10000
summaryIncome <-list("yearly income" =
list("Min"= ~ min(income),
"Max"= ~ max(income),
"Q1"= ~ quantile(income,0.25),
"Median"= ~ round(median(income),2),
"Q3"= ~ quantile(income,0.75),
"Mean"= ~ round(mean(income),2),
"Sd"= ~ round(sd(income),2),
"IQR"= ~ round(iqr(income),2),
"Var %"= ~ round((100 * sd(income)/mean(income)),2),
"IQR Var %"= ~ round((100 * 0.5 * iqr(income)/median(income)),2),
"Skewness"= ~ round(skew(income),2),
"Kurtosis"= ~ round(kurtosi(income),2)
))
summaryIncome<-summary_table(CreditCard, summaries = summaryIncome, by = c("card"))
kbl(summaryIncome, digits=1, caption="Table 1. Yearly Income [in USD] in regards to credit card application acceptance", col.names = c('application', 'not Accepted', 'Accepted')) %>% kable_classic(full_width = F, html_font = "Cambria") %>% kable_styling(bootstrap_options = c("striped", "hover"))| application | not Accepted | Accepted |
|---|---|---|
| yearly income | | |
| Min | 4900 | 2100 |
| Max | 110000 | 135000 |
| Q1 | 20000 | 23500 |
| Median | 25800 | 30000 |
| Q3 | 36500 | 40000 |
| Mean | 30687.41 | 34538.47 |
| Sd | 16180.76 | 17107.39 |
| IQR | 16500 | 16500 |
| Var % | 52.73 | 49.53 |
| IQR Var % | 31.98 | 27.5 |
| Skewness | 2.04 | 1.9 |
| Kurtosis | 5.21 | 4.83 |
Below you can see summary table of age in regards to application acceptance as continuation of its analysis. The level of dispersion around the mean is bigger for accepted applicants. We can confirm positive skewness that was noticed on graph as well as range being bigger for accepted applicants. Group of applicants that were accepted for credit card tends to be slightly older than not accepted group, but that is not an explicit difference, so it could not be that significant.
summaryAge <-list("Age" =
list("Min"= ~ min(age),
"Max"= ~ max(age),
"Q1"= ~ quantile(age,0.25),
"Median"= ~ round(median(age),2),
"Q3"= ~ quantile(age,0.75),
"Mean"= ~ round(mean(age),2),
"Sd"= ~ round(sd(age),2),
"IQR"= ~ round(iqr(age),2),
"Sx"= ~ round(iqr(age)/2,2),
"Var %"= ~ round((100 * sd(age)/mean(age)),2),
"IQR Var %"= ~ round((100 * 0.5 * iqr(age)/median(age)),2),
"Skewness"= ~ round(skew(age),2),
"Kurtosis"= ~ round(kurtosi(age),2)
))
summaryAge<-summary_table(CreditCard, summaries = summaryAge, by = c("card"))
kbl(summaryAge, digits=1, caption="Table 2. Age in regards to credit card application acceptance", col.names = c('application', 'not Accepted', 'Accepted')) %>% kable_classic(full_width = F, html_font = "Cambria") %>% kable_styling(bootstrap_options = c("striped", "hover"))| application | not Accepted | Accepted |
|---|---|---|
| Age | | |
| Min | 19 | 18.16667 |
| Max | 80.16666 | 83.5 |
| Q1 | 25.75 | 25.41667 |
| Median | 31.92 | 31.25 |
| Q3 | 38.125 | 39.75 |
| Mean | 33.31 | 33.41 |
| Sd | 9.76 | 9.93 |
| IQR | 12.38 | 14.33 |
| Sx | 6.19 | 7.17 |
| Var % | 29.28 | 29.71 |
| IQR Var % | 19.39 | 22.93 |
| Skewness | 1.25 | 1 |
| Kurtosis | 2.29 | 0.97 |
To answer the question and summarize report, as far as ratio of monthly credit card expenditure to yearly income and average monthly credit card expenditure are concerned, they depend strongly on being accepted for credit card application, therefore differ in between accepted and not accepted group. Applicants accepted for credit card tend to have bigger income then those not accepted. Share of people that do not own their own home is bigger within applicants that were not accepted, as well as share of people that are self-employed. Age of accepted and not accepted applicants does not differ significantly. Accepted group consists of less applicants with major derogatory reports and no applicants with bigger number of such reports. Accepted applicants more often have major credit card. Share of declined applications tends to be bigger with bigger number of dependants. When it comes to months living at current address, only with smaller group that have been living at current address for long time we can see some markable difference - they tend to be more frequently in accepted group of applicants.