Data
From Stigler’s

Frequency Table
- 케틀레가 작성한 스코틀랜드 군인 5738명의 가슴둘레(인치) 분포표를 옮기면
chest <- 33:48
freq <- c(3, 18, 81, 185, 420, 749, 1073, 1079, 934, 658, 370, 92, 50, 21, 4, 1)
data.frame(chest, freq)
## chest freq
## 1 33 3
## 2 34 18
## 3 35 81
## 4 36 185
## 5 37 420
## 6 38 749
## 7 39 1073
## 8 40 1079
## 9 41 934
## 10 42 658
## 11 43 370
## 12 44 92
## 13 45 50
## 14 46 21
## 15 47 4
## 16 48 1
data.frame(Chest = chest, Freq = freq)
## Chest Freq
## 1 33 3
## 2 34 18
## 3 35 81
## 4 36 185
## 5 37 420
## 6 38 749
## 7 39 1073
## 8 40 1079
## 9 41 934
## 10 42 658
## 11 43 370
## 12 44 92
## 13 45 50
## 14 46 21
## 15 47 4
## 16 48 1
chest.table <- data.frame(Chest = chest, Freq = freq)
chest.table
## Chest Freq
## 1 33 3
## 2 34 18
## 3 35 81
## 4 36 185
## 5 37 420
## 6 38 749
## 7 39 1073
## 8 40 1079
## 9 41 934
## 10 42 658
## 11 43 370
## 12 44 92
## 13 45 50
## 14 46 21
## 15 47 4
## 16 48 1
str(chest.table)
## 'data.frame': 16 obs. of 2 variables:
## $ Chest: int 33 34 35 36 37 38 39 40 41 42 ...
## $ Freq : num 3 18 81 185 420 ...
Probability Histogram
barplot(height, ...)
은 기본적으로 height
만 주어지면 그릴 수 있음. 확률 히스토그램의 기둥 면적의 합은 1이므로, 각 기둥의 높이는 각 계급의 돗수를 전체 돗수, 5738명으로 나눠준 값임.
total <- sum(chest.table$Freq)
barplot(chest.table$Freq/total)

- 각 막대의 이름은 계급을 나타내는 가슴둘레 값으로 표현할 수 있고, 막대 간의 사이를 띄우지 않으며, 디폴트 값으로 주어진 회색 보다는 차라리 백색이 나으므로 이를 설정해 주면,
barplot(chest.table$Freq/total, names.arg = 33:48, space = 0, col = "white")

- 확률 히스토그램의 정의에 따라 이 막대들의 면적을 합하면 1이 됨에 유의.
Summary statistics and SD
- 33인치가 3명, 34인치가 18명 등을 한 줄의 긴 벡터로 나타내어야 평균과 표준편차를 쉽게 계산할 수 있으므로 long format으로 바꾸면,
chest.long <- rep(chest.table$Chest, chest.table$Freq)
str(chest.long)
## int [1:5738] 33 33 33 34 34 34 34 34 34 34 ...
rep()
rep(1:3, 3)
## [1] 1 2 3 1 2 3 1 2 3
rep(1:3, each = 3)
## [1] 1 1 1 2 2 2 3 3 3
rep(1:3, 1:3)
## [1] 1 2 2 3 3 3
chest.long
을 이용하여 기초통계와 표준편차를 계산하면,
summary(chest.long)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 33.00 38.00 40.00 39.83 41.00 48.00
sd(chest.long)
## [1] 2.049616
Histogram
- 히스토그램을 직관적으로 그려보면 \(y\)축은 돗수가 기본값임을 알 수 있음.
hist(chest.long)

- 정규분포와 비교하기 위해서 \(y\)축을 확률로 나타내려면
hist(chest.long, probability = TRUE)

Inside the histogram
- 실제로 이 히스토그램을 그리는 데 계산된 값들은?
(h.chest <- hist(chest.long, plot = FALSE))
## $breaks
## [1] 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
##
## $counts
## [1] 21 81 185 420 749 1073 1079 934 658 370 92 50 21 4
## [15] 1
##
## $density
## [1] 0.0036598118 0.0141164169 0.0322411990 0.0731962356 0.1305332869
## [6] 0.1869989543 0.1880446148 0.1627744859 0.1146741025 0.0644823980
## [11] 0.0160334611 0.0087138376 0.0036598118 0.0006971070 0.0001742768
##
## $mids
## [1] 33.5 34.5 35.5 36.5 37.5 38.5 39.5 40.5 41.5 42.5 43.5 44.5 45.5 46.5
## [15] 47.5
##
## $xname
## [1] "chest.long"
##
## $equidist
## [1] TRUE
##
## attr(,"class")
## [1] "histogram"
list(breaks = h.chest$breaks, counts = h.chest$counts, density = h.chest$density, mids = h.chest$mids)
## $breaks
## [1] 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
##
## $counts
## [1] 21 81 185 420 749 1073 1079 934 658 370 92 50 21 4
## [15] 1
##
## $density
## [1] 0.0036598118 0.0141164169 0.0322411990 0.0731962356 0.1305332869
## [6] 0.1869989543 0.1880446148 0.1627744859 0.1146741025 0.0644823980
## [11] 0.0160334611 0.0087138376 0.0036598118 0.0006971070 0.0001742768
##
## $mids
## [1] 33.5 34.5 35.5 36.5 37.5 38.5 39.5 40.5 41.5 42.5 43.5 44.5 45.5 46.5
## [15] 47.5
- 평균값과 표준편차로부터 히스토그램의 위치가 0.5만큼 왼쪽으로 치우쳐 있다는 것을 알 수 있음. 제자리에 옮겨 놓기 위해서
breaks
매개변수를 32.5부터 48.5까지 1간격으로 설정
hist(chest.long, probability = TRUE, breaks = 32.5:48.5)

h.chest.2 <- hist(chest.long, breaks = 32.5:48.5, plot = FALSE)
list(breaks = h.chest.2$breaks, counts = h.chest.2$counts, density = h.chest.2$density, mids = h.chest.2$mids)
## $breaks
## [1] 32.5 33.5 34.5 35.5 36.5 37.5 38.5 39.5 40.5 41.5 42.5 43.5 44.5 45.5
## [15] 46.5 47.5 48.5
##
## $counts
## [1] 3 18 81 185 420 749 1073 1079 934 658 370 92 50 21
## [15] 4 1
##
## $density
## [1] 0.0005228303 0.0031369815 0.0141164169 0.0322411990 0.0731962356
## [6] 0.1305332869 0.1869989543 0.1880446148 0.1627744859 0.1146741025
## [11] 0.0644823980 0.0160334611 0.0087138376 0.0036598118 0.0006971070
## [16] 0.0001742768
##
## $mids
## [1] 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
- 히스토그램을 보기 쉽게 하기 위해서 메인 타이틀과 서브 타이틀, x축 라벨, y축 라벨 설정
main.title <- "Fitting Normal Distribution"
# sub.title <- "Chest Circumferences of Scottish Soldiers"
sub.title <- ""
x.lab <- "Chest Circumferences (inches)"
y.lab <- "Proportion"
hist(chest.long, breaks = 32.5:48.5, probability = TRUE, main = main.title, sub = sub.title, xlab = x.lab, ylab = y.lab)

Mean \(\pm\) SD contains 2/3 of total number of counts
- 평균을 중심으로 \(\pm\)표준편차 만큼 떨어진 자료를 붉은 색 수직점선으로 표시.
mean.chest <- mean(chest.long)
sd.chest <- sd(chest.long)
x.lower <- mean.chest - sd.chest
x.upper <- mean.chest + sd.chest
hist(chest.long, breaks = 32.5:48.5, probability = TRUE, main = main.title, sub = sub.title, xlab = x.lab, ylab = y.lab)
abline(v = c(x.lower, x.upper), lty = 2, col = "red")

- 그 사이의 영역을 빗금으로 표시하기 위하여 다각형의 좌표를 계산
h.chest.2$density[6:10]
## [1] 0.1305333 0.1869990 0.1880446 0.1627745 0.1146741
y <- h.chest.2$density[6:10]
- 5개의 직사각형으로 파악하고 향후 면적 계산을 쉽게 하기 위하여 다음과 같이 좌표 설정
x.coord <- rep(c(x.lower, 38.5:41.5, x.upper), each = 2)
y.coord <- c(0, rep(y, each = 2), 0)
poly.df <- data.frame(x = x.coord, y = y.coord)
hist(chest.long, breaks = 32.5:48.5, probability = TRUE, main = main.title, sub = sub.title, xlab = x.lab, ylab = y.lab)
abline(v = c(x.lower, x.upper), lty = 2, col = "red")
# polygon(x.coord, y.coord, density = 20)
polygon(poly.df, density = 20)

- 이론적으로 빗금친 부분의 면적은
pnorm(1) - pnorm(-1) =
0.6826895에 가까울 것으로 예상. 5개 직사각형의 면적을 구하여 합하는 과정은 다음과 같음.
options(digits = 2)
x.area <- c(x.lower, 38.5:41.5, x.upper)
y
## [1] 0.13 0.19 0.19 0.16 0.11
diff(x.area)
## [1] 0.72 1.00 1.00 1.00 0.38
diff(x.area) * y
## [1] 0.094 0.187 0.188 0.163 0.044
sum(diff(x.area) * y)
## [1] 0.68
Comparison with normal curve
- 이론적인 정규분포 밀도함수 곡선을 히스토그램에 덧붙여 그림.
x.chest <- seq(32.5, 48.5, length = 1000)
y.norm <- dnorm(x.chest, mean = mean.chest, sd = sd.chest)
hist(chest.long, breaks = 32.5:48.5, probability = TRUE, main = main.title, sub = sub.title, xlab = x.lab, ylab = y.lab)
abline(v = c(x.lower, x.upper), lty = 2, col = "red")
# abline(v = c(38, 42), lty = 2, col = "red")
polygon(poly.df, density = 20)
# polygon(x.coord, y.coord, density = 20)
lines(x.chest, y.norm, col = "red")

Changing tick marks of x axis
- default로 주어지는 \(x\)축의 눈금을 제대로 볼 수 있게 고치려면,
hist(chest.long, breaks = 32.5:48.5, probability = TRUE, main = main.title, sub = sub.title, xlab = x.lab, ylab = y.lab, axes = FALSE)
abline(v = c(x.lower, x.upper), lty = 2, col = "red")
polygon(poly.df, density = 20)
# polygon(x.coord, y.coord, density = 20)
lines(x.chest, y.norm, col = "red")
axis(side = 1, at = seq(32, 48, by = 2), labels = seq(32, 48, by = 2))
axis(side = 2)

ggplot
Basic histogram
library(ggplot2)
# theme_update(plot.title = element_text(hjust = 0.5))
g0 <- ggplot(data = data.frame(chest.long), mapping = aes(x = chest.long))
(g1 <- g0 +
stat_bin(aes(y = ..density..), binwidth = 1, fill = "white", colour = "black"))

# (g1 <- g0 +
# stat_count(fill = "white", colour = "black"))
# (g1 <- g0 +
# geom_histogram(aes(y = ..density..), binwidth = 1, fill = "white", colour = "black"))
# (g1 <- g0 +
# geom_histogram(aes(y = ..density..), binwidth = 1, breaks = 32.5:48.5, fill = "white", colour = "black"))
Mean \(\pm\) SD
(g2 <- g1 +
geom_vline(xintercept = c(x.lower, x.upper), linetype = "dotted", colour = "red"))

x-axis label and main title
(g3 <- g2 +
theme_bw() +
# xlab(x.lab) +
# ylab(y.lab) +
# ggtitle(main.title) +
labs(x = x.lab, y = y.lab, title = main.title) +
theme(plot.title = element_text(hjust = 0.5)))

Shading the area
(g4 <- g3 +
geom_polygon(data = poly.df, mapping = aes(x = x, y = y), alpha = 0.5, fill = "grey"))

Normal curve added
# x.curve <- seq(32.5, 48.5, length = 100)
# y.curve <- dnorm(x.curve, mean = mean.chest, sd = sd.chest)
curve.df <- data.frame(x = x.chest, y = y.norm)
(g5 <- g4 +
geom_line(data = curve.df, mapping = aes(x = x, y = y), colour = "blue"))

x-axis tick marks
(g6 <- g5 +
scale_x_continuous(breaks = seq(32, 48, by = 2), labels = seq(32, 48, by = 2)))
