[데이터시각화] 7. ggplot2
by Rev_시간시각화
libarary(ggplot2)
libarary(gcookbook)
data(climate) # gcookbook에 내장된 데이터셋
> str(climate)
'data.frame': 499 obs. of 6 variables:
$ Source : chr "Berkeley" "Berkeley" "Berkeley" "Berkeley" ...
$ Year : num 1800 1801 1802 1803 1804 ...
$ Anomaly1y : num NA NA NA NA NA NA NA NA NA NA ...
$ Anomaly5y : num NA NA NA NA NA NA NA NA NA NA ...
$ Anomaly10y: num -0.435 -0.453 -0.46 -0.493 -0.536 -0.541 -0.59 -0.695 -0.763 -0.818 ...
$ Unc10y : num 0.505 0.493 0.486 0.489 0.483 0.475 0.468 0.461 0.453 0.451 ...
499 X 6인 climate 데이터를 불러왔다.
지구 기후 온도 이상 데이터이다.
climate$pos <- climate$Anomaly10y >= 0
> str(climate)
'data.frame': 499 obs. of 7 variables:
$ Source : chr "Berkeley" "Berkeley" "Berkeley" "Berkeley" ...
$ Year : num 1800 1801 1802 1803 1804 ...
$ Anomaly1y : num NA NA NA NA NA NA NA NA NA NA ...
$ Anomaly5y : num NA NA NA NA NA NA NA NA NA NA ...
$ Anomaly10y: num -0.435 -0.453 -0.46 -0.493 -0.536 -0.541 -0.59 -0.695 -0.763 -0.818 ...
$ Unc10y : num 0.505 0.493 0.486 0.489 0.483 0.475 0.468 0.461 0.453 0.451 ...
$ pos : logi FALSE FALSE FALSE FALSE FALSE FALSE ...
위는 climate 데이터에서 Anomaly10y 변수가 0이상이면 새로운 pos 변수에 True, 미만이면 pos에 False를 할당하게 된다. 다시 str(climate)를 통하여 살펴보면 새로운 pos 변수가 생성되었다.
ggplot(data = climate, aes(x=Year, y=Anomaly10y, fill=pos)) +
geom_bar(stat="identity", position="identity")
1925년 이전에는 Anomaly10y 값이 음수로 등락을 반복하면서 증가하는 추세이고, 1925년 이후에는 Anomaly10y 값이 양수로 증가하면서, 1975년 이후부터는 빠른 속도로 증가하는 추세를 보이고 있음
ggplot(data = climate, aes(x=Year, y=Anomaly10y)) + geom_line() + geom_point()
선 + 점 그래프
ggplot(data = climate, aes(x=Year, y=Anomaly10y)) +
geom_ribbon(aes(ymin=Anomaly10y-Unc10y, ymax = Anomaly10y+Unc10y), alpha = 0.2) +
geom_line()
선 그래프 + 신뢰구간을 나타냈다.
과거에는 신뢰구간의 폭이 크게 나타났으나, 최근으로 올수록 신뢰구간의 폭은 좁아지는 경향을 보인다. 신뢰구간의 폭이 좁아지는 것의 의미는 불확실성이 감소했다는 것을 의미한다.
즉, 예측의 정확성이 1850년도부터 높아졌음을 알 수 있다.
wdiData <- read.csv("C:/BNG/WorldBank_asia.csv", header=T)
ggplot(data = wdiData, aes(x=year, y=fertility.rate, col=iso2c)) + geom_line()
아시아 국가의 출산률을 비교하는 그래프를 그려보았다.
x값은 year, y값은 fertility.rate로 설정하였고, iso2c별로 색을 구분하였다.
ggplot(data = wdiData, aes(x=year, y=fertility.rate, shape=iso2c, col=iso2c))
+ geom_line() + geom_point(size = 1)
shape로 선 그래프와 점 그래프의 모양을 설정해주었다.
ggplot(data = wdiData, aes(x=year, y=fertility.rate, shape=iso2c, col=iso2c))
+ geom_line() + geom_point(size = 1) + facet_grid(iso2c~.)
facet_grid()로 범주형 변수의 범주에 따라 구분해서 그래프를 그렸다.
시간이 지남에 따라서 중국, 일본, 북한, 한국의 출산률을 비교한 결과를 시각화해보았는데, 우리나라가 다른 국가들에 비해서 가장 빠른 속도로 출산률이 감소하는 것을 알 수 있다.
밀도시각화
library(ggplot2)
ggplot(data=diamonds) + geom_bin2d(mapping = aes(x = carat, y = price),
binwidth = c(0.1, 500))
geom_bin2d()는 산점도에서 시각화할 때 밀도 정보를 표현할 수 있는 그래프이다.
각 bin에 점이 몇개 포함되어 있느냐에 따라 직사각형 모양으로 해당 bin의 색깔을 각각 다르게 표시한다.
그리고 x축 변수는 0.1 크기로 구간화하였고, y축 변수는 500 크기로 구간화하였다.
# install.packages("hexbin")
ggplot(data = diamonds) + geom_hex(mapping = aes(x = carat, y = price),
binwidth = c(0.1, 500))
geom_hex()는 산점도에서 밀도의 정보를 표현할 때 점의 모양을 육각형으로 표현한다.
ggplot(data = diamonds) + geom_hex(mapping = aes(x = carat, y = price),
binwidth = c(0.05, 500))
위와 같이 구간 간격을 더 작게 하면 더 섬세하게 표현할 수 있다.
이들은 모두 산점도에서 색깔의 진하기 정도에 따라서 데이터의 밀집된 정도를 표현한 밀도 시각화이다. 데이터가 가장 많이 밀집되어 있는 위치는 원점 근처이며, 이는 무게도 작고 가격도 낮은 다이아몬드가 가장 빈도가 많은 것을 의미한다.
무게와 가격 간의 관계를 시각화 하기 위해서 일반적으로 산점도를 사용하는데, 여기에 밀도 정보까지 추가한 것이다. 데이터의 개수가 많을 때는 가능하면 밀도정보까지 추가하는 것이 더 많은 정보를 표현할 수 있다.
ggplot(data = diamonds) + geom_hex(mapping = aes(x = carat, y = price),
binwidth = c(0.05, 200)) + scale_fill_gradientn(colours = c("black", "yellow", "white"))
scale_fill_gradientn()는 밀도의 정보에 맞게 점의 색깔을 지정한다.
오른쪽으로 갈수록 밀도가 높은 색깔을 설정한다.
library(hexbin) # data NHANES를 내장하고 있음
data(NHANES)
> str(NHANES)
'data.frame': 9575 obs. of 15 variables:
$ Cancer.Incidence: Factor w/ 2 levels "No","Yes": 1 1 1 1 1 1 1 1 1 1 ...
$ Cancer.Death : Factor w/ 2 levels "No","Yes": 1 1 1 1 1 1 1 1 1 1 ...
$ Age : num 46 72 53 49 31 42 27 64 37 42 ...
$ Smoke : Factor w/ 4 levels "Current","Past",..: 3 4 2 4 1 1 1 4 3 2 ...
$ Ed : num 0 0 1 0 0 1 0 0 1 1 ...
$ Race : num 0 0 1 1 1 1 0 0 0 1 ...
$ Weight : num 82.7 85.6 71.5 93.8 81.6 68.3 67.7 86.5 61.7 85 ...
$ BMI : num 29.4 29.6 23.1 30 29.7 21.9 26.3 31.9 20.9 26.7 ...
$ Diet.Iron : num 12.5 NA 14.8 24.3 11.8 25.3 25.2 6.8 26.2 11 ...
$ Albumin : num 4.8 4.1 NA 4.3 4.3 4.8 4.3 3.9 4.4 4.7 ...
$ Serum.Iron : num NA NA 135 85 104 124 68 NA 69 89 ...
$ TIBC : num NA NA 334 385 436 285 468 NA 291 456 ...
$ Transferin : num NA NA 40.4 22.1 23.9 43.5 14.5 NA 23.7 19.5 ...
$ Hemoglobin : num 14.7 14.5 16.8 16 16.1 17.1 14.3 15 15.2 16.3 ...
$ Sex : Factor w/ 2 levels "F","M": 2 2 2 2 2 2 2 2 2 2 ...
9575 X 15 로 이루어진 NHANES 데이터이다.
이 데이터를 통하여 Weight와 BMI 간의 관련성을 시각화 해보도록 하자.
ggplot(data = NHANES) + geom_bin2d(mapping = aes(x = Weight, y = BMI),
binwidth = c(1.5, 0.5)) + scale_fill_gradientn(colours = c("black", "yellow", "white"))
몸무게가 증가할수록 BMI 지수는 증가하는 패턴을 보이고 있다.
데이터의 밀도는 몸무게가 60~90, BMI는 약 20~30 사이에 높게 나타남
ggplot(data = NHANES) + geom_bin2d(mapping = aes(x = Weight, y = BMI),
binwidth = c(1.5, 0.3)) + scale_fill_gradientn("", colour = c("black", "blue", "white"))
+ facet_wrap(~ Race)
facet_wrap()을 사용하여 범주별로 밀도정보를 분리해서 시각화하였다.
체중이 증가할수록 BMI는 인종에 관계없이 증가하는 추세이지만, 인종이 1일 때 밀도에 대한 정보가 뚜렷하게 보이나 인종이 0일 때는 밀도에 대한 정보가 거의 없는 것으로 나타났다.
ggplot(data = NHANES, aes(x = Weight, y = BMI)) + geom_point(col = "black")
+ stat_density2d(col = "white")
stat_density2d()를 통해 등고선을 표시할 수 있다.
ggplot(data = NHANES, aes(x = Wright, y = BMI)) + stat_binhex(bins=70)
+ scale_fill_gradientn(colours = c("blue", "yellow", "white"))
stat_binhex()는 bin2d의 육각형 버전이다.
bins는 구간의 개수를 설정한다.
ggplot(data = NHANES, aes(x = Weight, y = BMI)) + stat_binhex(bins = 70)
+ scale_fill_gradientn(colours = c("blue", "yellow", "white"))
+ facet_grid(. ~ Smoke)
facet_grid()에서 ~의 오른쪽에 변수가 있으면 Smoke별 데이터를 가로로 배열한다.
ggplot(data = NHANES, aes(x = Weight, y = BMI)) + stat_binhex(bin = 70)
+ scale_fill_gradientn(colours = c("blue", "yellow", "white"))
+ facet_grid(Smoke ~ .)
facet_grid()에서 ~의 왼쪽에 변수가 있으면 Smoke별로 세로로 배열한다.
ggplot(data = NHANES, aes(x = Weight, y = BMI)) + stat_binhex(bins = 70)
+ scale_fill_gradientn(colours = c("blue", "yellow", "white"))
+ facet_grid(Cancer.Incidence ~ Smoke)
~의 왼쪽은 암발병 여부, ~ 오른쪽은 흡연여부로 각각 분리하여 그래프를 그렸다.
버블차트
library(ggplot2)
library(gcookbook) # gcookbook : 다양한 예제 데이터를 내장하고 있음
data(heightweight)
> str(heightweight)
'data.frame': 236 obs. of 5 variables:
$ sex : Factor w/ 2 levels "f","m": 1 1 1 1 1 1 1 1 1 1 ...
$ ageYear : num 11.9 12.9 12.8 13.4 15.9 ...
$ ageMonth: int 143 155 153 161 191 171 185 142 160 140 ...
$ heightIn: num 56.3 62.3 63.3 59 62.5 62.5 59 56.5 62 53.8 ...
$ weightLb: num 85 105 108 92 112 ...
heightweight는 236 X 5로 이루어진 데이터이다.
학생들의 키와 몸무게 데이터이다.
ggplot(data = heightweight, aes(x=weightLb, y=heightIn, fill=ageYear))
+ geom_point(shape=21, size=2.5)
+ scale_fill_gradient(low="white", high="black")
X축을 몸무게로 하고, Y축을 키, 연령별로 색깔을 구분한 3차원 그래프이다.
점 모양은 21번 모양으로 하였고, 점 크기는 2.5로 설정하였다.
scale_fill_gradient()를 사용하여 색깔을 점진적으로 표현하였다. 색깔변수(fill)가 연령으로 연속형이기 때문에 연령이 낮을수록 흰색 톤으로, 연령이 높을수록 높은색 톤으로 표현된다.
ggplot(data=heightweight, aes(x=ageYear, y=heightIn, size=weightLb, colour=sex))
+ geom_point(alpha=0.4)
X축은 나이, Y축은 키, 점 크기는 몸무게, 점 색깔은 성별을 의미하는 4차원 그래프이다.
몸무게가 큰 사람은 나이도 많고 키도 큰 사람인 경향이 있다.
나이가 작을수록 점의 크기도 작고, 점의 색깔도 많이 섞여 있다.
즉, 나이가 작을수록 점의 크기도 작고, 남녀의 키와 몸무게 구분이 잘 되지 않지만 나이가 많아질수록 점의 크기가 커지고 파란색 점(남성)들이 붉은색 점(여성)들보다 더 상단에 분포되어 있다.
ggplot(heightweight, aes(x=ageYear, y=heightIn, size=weightLb, colour=ageMonth))
+ geom_point(alpha=0.8)
+ scale_colour_gradientn(colours = c("white", "yellow", "orange", "darkred"))
hw <- heightweight
hw$weightGroup <- cut(hw$weightLb, breaks=c(-Inf, 100, Inf), labels=c("< 100", ">= 100"))
cut 변수는 연속형 변수를 구간화하기 위함이다.
breaks를 통해 구간화할 수 있는데, -무한대에서 100까지, 100부터 무한대까지로 총 2개의 구간으로 나눴다. 이를 각각 <100과 >= 100으로 이름을 붙였다.
ggplot(data=hw, aes(x=ageYear, y=heightIn, shape=sex, fill=weightGroup))
+ geom_point(size=2.5)
+ scale_shape_manual(values=c(21, 24))
+ scale_fill_manual(values=c("yellow", "black"),
guide=guide_legend(override.aes=list(shape=21)))
x는 나이, y는 키로 설정한다. 성별별로 모양을 다르게 지정하도록 하였다. 그리고 새로 만든 변수인 weightGroup을 색깔로 구분하도록 하였다.
scale_shape_manual()은 점의 모양 구분이 성별로 범주형 변수이므로, 점의 모양을 어떤것을 사용할지 지정하는 함수이다.
scale_fill_manual()은 점의 색깔 구분이 체중그룹으로 범주형 변수이므로, 점의 색깔을 어떻게 지정할 것인지 구분한다. 그리고 guide=guide_legend(override.aes=list(shape=21))는 첫번째 범주를 점모양 21로 하겠다는 의미이다.
연령이 증가할수록 키가 증가하는 경향이 있다.
검은색이 노란색에 비해 대체로 위쪽에 위치하는데, 체중그룹이 100이상인 경우가 100미만인 경우보다 동일한 연령에서 키가 더 크다는 것을 의미한다.
그리고 삼각형이 원에 비해서 대체로 위쪽에 위치하는데, 여자에 비해서 남자가 동일한 연령에서 키가 더 크다는 것을 의미한다.
키와 나이가 적은 사람은 노란색 원과 삼각형이 많고, 키와 나이가 많은 사람은 검은색 삼각형이 많다.
ggplot(data=hw, aes(x=ageYear, y=heightIn, shape=weightGroup, size=weightLb, colour=ageMonth))
+ geom_point(alpha=1) + scale_shape_manual(values=c(15, 17))
+ scale_colour_gradientn(colours = c("white", "yellow", "orange", "darkred"))
+ ggtitle("Bubble Chart for height/weight")
data <- read.csv("C:/BNG/education.csv", header=T)
> str(data)
'data.frame': 50 obs. of 9 variables:
$ state : chr "Alabama" "Alaska" "Arizona" "Arkansas" ...
$ reading : int 557 520 516 572 500 568 509 495 497 490 ...
$ math : int 552 516 521 572 513 575 513 498 498 491 ...
$ writing : int 549 492 497 556 498 555 512 484 480 479 ...
$ percent_graduates_sat: int 7 46 26 5 49 20 83 71 59 71 ...
$ pupil_staff_ratio : num 6.7 7.9 10.4 6.8 10.9 8.1 6.6 7.9 8.1 7 ...
$ dropout_rate : num 2.3 7.3 7.6 4.6 5.5 6.9 2.1 5.5 3.8 4.6 ...
$ Latitude : num 32.8 61.4 33.7 35 36.1 ...
$ Longitude : num -86.8 -152.4 -111.4 -92.4 -119.7 ...
이번에는 50 X 9인 education 데이터로 시각화를 해보자.
ggplot(data=data, aes(x=reading, y=writing, size=pupil_staff_ratio, colour=math))
+ geom_point(alpha=0.5)
+ scale_colour_gradientn(colours=c("yellow", "orange", "brown", "darkred"))
X축은 읽기, Y축은 쓰기, 점 크기는 교사학생비율, 점 색깔을 수학 성적을 비교한 그래프이다.
읽기 점수가 증가할수록 쓰기 점수가 증가하는 경향이 있다. 색깔이 위로 갈수록 점점 진해지는 것을 보아하니 읽기 성적과 쓰기 성적이 증가할수록 수학성적도 증가하는 경향이 있다.
그러나 교사 학생 비율에 따라서 성적의 연관성은 찾기 힘든것 같다.
ggplot(data=data, aes(x=reading, y=writing, size=pupil_staff_ratio, colour=math))
+ geom_point(alpha=0.5) + geom_smooth(method="lm", se=TRUE)
geom_smooth()를 사용하여 추세선을 추가할 수 있다.
method = "loess"로 변경해주면 직선이 아닌 곡선이 된다.
ggplot(data=data, aes(x=reading, y=writing, size=pupil_staff_ratio, colour=math))
+ geom_point(alpha=0.5) + geom_smooth(method = "lm", se = TRUE)
+ scale_colour_gradientn(colours = c("yellow", "orange", "brown", "darkred"))
+ geom_text(aes(x=reading+3, label=state), size=2.5, hjust=0)
geom_text()를 통해 그래프에 텍스트를 추가했다.
텍스트의 내용은 state 이름이 나오도록 하였고, hjust는 점의 위치와 동일한 높이에 텍스트를 표시하라는 의미이다.
data$group <= cut(data&reading, break=c(-Inf, 500, Inf), labels=c("< 500", ">= 500"))
> str(data)
'data.frame': 50 obs. of 10 variables:
$ state : chr "Alabama" "Alaska" "Arizona" "Arkansas" ...
$ reading : int 557 520 516 572 500 568 509 495 497 490 ...
$ math : int 552 516 521 572 513 575 513 498 498 491 ...
$ writing : int 549 492 497 556 498 555 512 484 480 479 ...
$ percent_graduates_sat: int 7 46 26 5 49 20 83 71 59 71 ...
$ pupil_staff_ratio : num 6.7 7.9 10.4 6.8 10.9 8.1 6.6 7.9 8.1 7 ...
$ dropout_rate : num 2.3 7.3 7.6 4.6 5.5 6.9 2.1 5.5 3.8 4.6 ...
$ Latitude : num 32.8 61.4 33.7 35 36.1 ...
$ Longitude : num -86.8 -152.4 -111.4 -92.4 -119.7 ...
$ group : Factor w/ 2 levels "< 500",">= 500": 2 2 2 2 1 2 2 1 1 1 ...
reading 변수를 500 전 후로 구간화 한 범주형 데이터를 group 변수로 저장했다.
ggplot(data=data, aes(x=reading, y=writing, size=pupil_staff_ratio, colour=math))
+ geom_point(alpha=0.5)
+ facet_wrap(~ group)
+ scale_colour_gradientn(colours = c("yellow", "orange", "brown", "darkred"))
+ geom_smooth(method="lm", se=TRUE)
+ geom_text(aes(x=reading+3, label=state), size=2, hjust=0)
facet_wrap()을 통해 구간화를 해주었다.
'복수전공' 카테고리의 다른 글
[조사방법론] 1. 과학적 조사와 연구 (0) | 2022.04.15 |
---|---|
[데이터시각화] 8. 지도 (0) | 2021.12.16 |
[범주형 데이터분석] 5. 텍스트 분석(NLP) (0) | 2021.12.02 |
[표본조사론] 3. 층화임의추출법 (0) | 2021.11.15 |
[현대사회의 데이터와 통계학] 5. Matplotlib로 그래프 그리기 (0) | 2021.11.10 |
블로그의 정보
Hi Rev
Rev_