From Stigler’s ‘History of Statistics’
knitr
패키지의 include_graphics()
이용markdown
이용Quetelet’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
# sapply(data.frame(chest, freq), typeof)
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 ...
chest_table$Freq
## [1] 3 18 81 185 420 749 1073 1079 934 658 370 92 50 21
## [15] 4 1
str(chest_table$Freq)
## num [1:16] 3 18 81 185 420 ...
chest_table[, 2]
## [1] 3 18 81 185 420 749 1073 1079 934 658 370 92 50 21
## [15] 4 1
str(chest_table[, 2])
## num [1:16] 3 18 81 185 420 ...
chest_table[, "Freq"]
## [1] 3 18 81 185 420 749 1073 1079 934 658 370 92 50 21
## [15] 4 1
str(chest_table[, "Freq"])
## num [1:16] 3 18 81 185 420 ...
chest_table["Freq"]
## Freq
## 1 3
## 2 18
## 3 81
## 4 185
## 5 420
## 6 749
## 7 1073
## 8 1079
## 9 934
## 10 658
## 11 370
## 12 92
## 13 50
## 14 21
## 15 4
## 16 1
str(chest_table["Freq"])
## 'data.frame': 16 obs. of 1 variable:
## $ Freq: num 3 18 81 185 420 ...
chest_table["Freq"]$Freq
## [1] 3 18 81 185 420 749 1073 1079 934 658 370 92 50 21
## [15] 4 1
str(chest_table["Freq"]$Freq)
## num [1:16] 3 18 81 185 420 ...
chest_table["Freq"][[1]]
## [1] 3 18 81 185 420 749 1073 1079 934 658 370 92 50 21
## [15] 4 1
str(chest_table["Freq"][[1]])
## num [1:16] 3 18 81 185 420 ...
chest_table[2]
## Freq
## 1 3
## 2 18
## 3 81
## 4 185
## 5 420
## 6 749
## 7 1073
## 8 1079
## 9 934
## 10 658
## 11 370
## 12 92
## 13 50
## 14 21
## 15 4
## 16 1
str(chest_table[2])
## 'data.frame': 16 obs. of 1 variable:
## $ Freq: num 3 18 81 185 420 ...
chest_table[2]$Freq
## [1] 3 18 81 185 420 749 1073 1079 934 658 370 92 50 21
## [15] 4 1
str(chest_table[2]$Freq)
## num [1:16] 3 18 81 185 420 ...
chest_table[2][[1]]
## [1] 3 18 81 185 420 749 1073 1079 934 658 370 92 50 21
## [15] 4 1
str(chest_table[2][[1]])
## num [1:16] 3 18 81 185 420 ...
chest_table[[2]]
## [1] 3 18 81 185 420 749 1073 1079 934 658 370 92 50 21
## [15] 4 1
str(chest_table[[2]])
## num [1:16] 3 18 81 185 420 ...
33인치인 사람이 3명, 34인치인 사람이 18명 등으로 기록되어 있으나 이는 구간의 가운데로 이해하여야 함.
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이 됨에 유의.
33인치가 3명, 34인치가 18명 등을 한 줄의 긴 벡터로 나타내어야 평균과 표준편차를 쉽게 계산할 수 있으므로 long format으로 바꾸면,
chest_long <- rep(chest_table$Chest, chest_table$Freq)
table(chest_long)
## chest_long
## 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
## 3 18 81 185 420 749 1073 1079 934 658 370 92 50 21 4
## 48
## 1
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
히스토그램을 직관적으로 그려보면 \(y\)축은 돗수가 기본값임을 알 수 있음.
hist(chest_long)
정규분포와 비교하기 위해서 \(y\)축을 확률로 나타내려면
hist(chest_long,
probability = TRUE)
실제로 이 히스토그램을 그리는 데 계산된 값들은?
(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)
평균을 중심으로 \(\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 = 10,
angle = 30,
col = "blue")
이론적으로 빗금친 부분의 면적은 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
이론적인 정규분포 밀도함수 곡선을 히스토그램에 덧붙여 그림.
x_chest <- seq(from = 32.5,
to = 48.5,
# by = 0.01,
# length.out = 1000,
along.with = chest_long)
# x_chest <- seq.along(chest_long)
y_norm <- dnorm(x_chest,
mean = mean_chest,
sd = sd_chest)
curve_df <- data.frame(x = x_chest, y = y_norm)
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(poly_df, density = 20)
lines(curve_df, col = "blue")
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(curve_df,
col = "red")
axis(side = 1,
at = seq(32, 48, by = 2),
labels = seq(32, 48, by = 2))
axis(side = 2)
ggplot
data frame으로 작업.
library(ggplot2)
# theme_update(plot.title = element_text(hjust = 0.5))
g0 <- ggplot(data = data.frame(chest_long),
mapping = aes(x = chest_long))
# g0
# (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"))
(g2 <- g1 +
geom_vline(xintercept = c(x_lower, x_upper),
linetype = "dotted",
colour = "red"))
(g3 <- g2 +
theme_bw() +
labs(x = x_lab, y = y_lab, title = main_title) +
theme(plot.title = element_text(hjust = 0.5)))
(g4 <- g3 +
geom_polygon(data = poly_df,
mapping = aes(x = x, y = y),
alpha = 0.2,
fill = "red"))
(g5 <- g4 +
geom_line(data = curve_df,
mapping = aes(x = x, y = y),
colour = "blue"))
(g6 <- g5 +
scale_x_continuous(name = "Chest (inches)",
breaks = seq(32, 48, by = 2),
labels = seq(32, 48, by = 2)))
# save(list = ls(), file = "./Quetelet_chest.RData")
save.image(file = "./Quetelet_chest.RData")