Day 3: 데이터 탐색과 시각화
오늘 사용할 패키지
tidyverse
ggrepel
patchwork
RColorBrewer
1 데이터 변형
1.1 실습 준비
사용할 데이터는 World Bank가 gapmider.org를 통해 무료로 배포하는 것으로 gapmider
패키지에 포함되어 있다. gapmider
패키지를 인스톨하고 불러온다. 데이터가 어떻게 구성되어 있는지 살펴본다.
1.2 행 함수
1.2.1 filter()
함수
특정 열(변수)과 관련된 조건을 만족하는 행을 선정한다. 행의 길이가 준다.
# continent의 값이 Europe인 행만 선택
gapminder |>
filter(continent == "Europe")
# A tibble: 360 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Albania Europe 1952 55.2 1282697 1601.
2 Albania Europe 1957 59.3 1476505 1942.
3 Albania Europe 1962 64.8 1728137 2313.
4 Albania Europe 1967 66.2 1984060 2760.
5 Albania Europe 1972 67.7 2263554 3313.
6 Albania Europe 1977 68.9 2509048 3533.
7 Albania Europe 1982 70.4 2780097 3631.
8 Albania Europe 1987 72 3075321 3739.
9 Albania Europe 1992 71.6 3326498 2497.
10 Albania Europe 1997 73.0 3428038 3193.
# ℹ 350 more rows
# pop이 5천만, gdpPercap이 3만을 초과하는 행만 선택
gapminder |>
filter(pop > 50000000 & gdpPercap > 30000)
# A tibble: 9 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 France Europe 2007 80.7 61083916 30470.
2 Germany Europe 2002 78.7 82350671 30036.
3 Germany Europe 2007 79.4 82400996 32170.
4 Japan Asia 2007 82.6 127467972 31656.
5 United Kingdom Europe 2007 79.4 60776238 33203.
6 United States Americas 1992 76.1 256894189 32004.
7 United States Americas 1997 76.8 272911760 35767.
8 United States Americas 2002 77.3 287675526 39097.
9 United States Americas 2007 78.2 301139947 42952.
# year이 2007이고, lifeExp가 82를 초과하거나 gdpPercap이 4만을 초과하는 행만 선택
gapminder |>
filter(year == 2007 & (lifeExp > 82 | gdpPercap > 40000))
# A tibble: 7 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Hong Kong, China Asia 2007 82.2 6980412 39725.
2 Ireland Europe 2007 78.9 4109086 40676.
3 Japan Asia 2007 82.6 127467972 31656.
4 Kuwait Asia 2007 77.6 2505559 47307.
5 Norway Europe 2007 80.2 4627926 49357.
6 Singapore Asia 2007 80.0 4553009 47143.
7 United States Americas 2007 78.2 301139947 42952.
1.2.2 slice()
함수
filter()
함수와 마찬가지로 행의 숫자를 줄인다. slice()
함수는 slice_head()
, slice_tail()
, slice_max()
, slice_min()
과 같은 패밀리 함수가 더 널리 사용된다. 그런데 이 함수들은 작동 방식에 따라 두 가지로 구분된다.
특정 열(변수)과 관계 없이, 행의 위치에 의거해 행을 선정:
slice()
,slice_head()
,slice_tail()
특정 열(변수)에 따른, 행의 위치에 의거해 행을 선정:
slice_max()
,slice_min()
몇 번째에서 몇 번째 사이의 행만을 골라낸다.
# 1~5행만을 선택
gapminder |>
slice(1:5)
# A tibble: 5 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Afghanistan Asia 1952 28.8 8425333 779.
2 Afghanistan Asia 1957 30.3 9240934 821.
3 Afghanistan Asia 1962 32.0 10267083 853.
4 Afghanistan Asia 1967 34.0 11537966 836.
5 Afghanistan Asia 1972 36.1 13079460 740.
가장 앞에 위치한 몇 개(n
)의 행만을 골라낸다. 실질적으로 위와 동일하다.
# 가장 앞의 5개 행을 선택
gapminder |>
slice_head(n = 5)
# A tibble: 5 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Afghanistan Asia 1952 28.8 8425333 779.
2 Afghanistan Asia 1957 30.3 9240934 821.
3 Afghanistan Asia 1962 32.0 10267083 853.
4 Afghanistan Asia 1967 34.0 11537966 836.
5 Afghanistan Asia 1972 36.1 13079460 740.
Base R 함수인 head()
또한 같은 역할을 할 수 있다.
gapminder |>
head(5)
# A tibble: 5 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Afghanistan Asia 1952 28.8 8425333 779.
2 Afghanistan Asia 1957 30.3 9240934 821.
3 Afghanistan Asia 1962 32.0 10267083 853.
4 Afghanistan Asia 1967 34.0 11537966 836.
5 Afghanistan Asia 1972 36.1 13079460 740.
가장 뒤에 위치한 몇 개(n
)의 행만을 골라낸다.
# 가장 뒤의 5개 행을 선택
gapminder |>
slice_tail(n = 5)
# A tibble: 5 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Zimbabwe Africa 1987 62.4 9216418 706.
2 Zimbabwe Africa 1992 60.4 10704340 693.
3 Zimbabwe Africa 1997 46.8 11404948 792.
4 Zimbabwe Africa 2002 40.0 11926563 672.
5 Zimbabwe Africa 2007 43.5 12311143 470.
Base R 함수인 tail()
또한 같은 역할을 할 수 있다.
gapminder |>
tail(5)
# A tibble: 5 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Zimbabwe Africa 1987 62.4 9216418 706.
2 Zimbabwe Africa 1992 60.4 10704340 693.
3 Zimbabwe Africa 1997 46.8 11404948 792.
4 Zimbabwe Africa 2002 40.0 11926563 672.
5 Zimbabwe Africa 2007 43.5 12311143 470.
특정 열(변수)에 따라 값이 가장 큰 몇 개(n
)의 행만을 골라낸다.
# 2007년에 gdpPercap이 가장 큰 5개국 찾기
gapminder |>
filter(year == 2007) |> # year이 2007인 행만 선택
slice_max(gdpPercap, n = 5) # gdpPercap이 가장 큰 5개 행 선택
# A tibble: 5 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Norway Europe 2007 80.2 4627926 49357.
2 Kuwait Asia 2007 77.6 2505559 47307.
3 Singapore Asia 2007 80.0 4553009 47143.
4 United States Americas 2007 78.2 301139947 42952.
5 Ireland Europe 2007 78.9 4109086 40676.
특정 열(변수)에 따라 값이 가장 작은 것들 중 주어진 비중(prop
)에 해당하는 행만을 골라낸다.
# 2007년 아시아에서 lifeExp가 하위 10%인 국가 찾기
gapminder |>
filter(year == 2007 & continent == "Asia") |> # year이 2007이고 continent가 Asia인 행만 선택
slice_min(lifeExp, prop = 0.1) # lifeExp가 작은 순으로 10% 행만 선택
# A tibble: 3 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Afghanistan Asia 2007 43.8 31889923 975.
2 Iraq Asia 2007 59.5 27499638 4471.
3 Cambodia Asia 2007 59.7 14131858 1714.
1.2.3 arrange()
함수
특정 열(변수)과 관련된 조건에 의거해 행의 순서를 바꾼다. 행의 길이에는 변화가 없다.
# lifeExp 오름차순으로 행 정렬
gapminder |>
arrange(lifeExp)
# A tibble: 1,704 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Rwanda Africa 1992 23.6 7290203 737.
2 Afghanistan Asia 1952 28.8 8425333 779.
3 Gambia Africa 1952 30 284320 485.
4 Angola Africa 1952 30.0 4232095 3521.
5 Sierra Leone Africa 1952 30.3 2143249 880.
6 Afghanistan Asia 1957 30.3 9240934 821.
7 Cambodia Asia 1977 31.2 6978607 525.
8 Mozambique Africa 1952 31.3 6446316 469.
9 Sierra Leone Africa 1957 31.6 2295678 1004.
10 Burkina Faso Africa 1952 32.0 4469979 543.
# ℹ 1,694 more rows
desc()
도우미 함수(helper function)는 내림차순으로 행을 배열한다.
# A tibble: 1,704 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Norway Europe 1952 72.7 3327728 10095.
2 Iceland Europe 1952 72.5 147962 7268.
3 Netherlands Europe 1952 72.1 10381988 8942.
4 Sweden Europe 1952 71.9 7124673 8528.
5 Denmark Europe 1952 70.8 4334000 9692.
6 Switzerland Europe 1952 69.6 4815000 14734.
7 New Zealand Oceania 1952 69.4 1994794 10557.
8 United Kingdom Europe 1952 69.2 50430000 9980.
9 Australia Oceania 1952 69.1 8691212 10040.
10 Canada Americas 1952 68.8 14785584 11367.
# ℹ 1,694 more rows
1.2.4 distinct()
함수
특정 열(변수)에 의거해 중복이 없이 고유한 행만을 골라낸다. 행의 길이가 준다.
# country 변수 안에 어떤 값들이 포함되어 있는지 확인
gapminder |>
distinct(country)
# A tibble: 142 × 1
country
<fct>
1 Afghanistan
2 Albania
3 Algeria
4 Angola
5 Argentina
6 Australia
7 Austria
8 Bahrain
9 Bangladesh
10 Belgium
# ℹ 132 more rows
.keep_all
아규먼트를 이용하면 나머지 열도 함께 나타낼 수 있다. 같은 값을 가진 행이 다수 존재한다면 가장 앞선 행을 보여준다.
# continent 변수 안에 어떤 값들이 포함되어 있는지 나머지 열과 함께 확인
gapminder |>
distinct(continent, .keep_all = TRUE)
# A tibble: 5 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Afghanistan Asia 1952 28.8 8425333 779.
2 Albania Europe 1952 55.2 1282697 1601.
3 Algeria Africa 1952 43.1 9279525 2449.
4 Argentina Americas 1952 62.5 17876956 5911.
5 Australia Oceania 1952 69.1 8691212 10040.
1.3 열 함수
1.3.1 select()
함수
열(변수)의 일부를 선택한다. 열의 길이가 준다.
# year, country, gdpPercap 변수만 선택
gapminder |>
select(year, country, gdpPercap)
# A tibble: 1,704 × 3
year country gdpPercap
<int> <fct> <dbl>
1 1952 Afghanistan 779.
2 1957 Afghanistan 821.
3 1962 Afghanistan 853.
4 1967 Afghanistan 836.
5 1972 Afghanistan 740.
6 1977 Afghanistan 786.
7 1982 Afghanistan 978.
8 1987 Afghanistan 852.
9 1992 Afghanistan 649.
10 1997 Afghanistan 635.
# ℹ 1,694 more rows
열(변수)의 일부를 선택하지 않는다. 역시 열의 길이가 준다. 실질적으로 위와 동일하다.
# A tibble: 1,704 × 3
country year gdpPercap
<fct> <int> <dbl>
1 Afghanistan 1952 779.
2 Afghanistan 1957 821.
3 Afghanistan 1962 853.
4 Afghanistan 1967 836.
5 Afghanistan 1972 740.
6 Afghanistan 1977 786.
7 Afghanistan 1982 978.
8 Afghanistan 1987 852.
9 Afghanistan 1992 649.
10 Afghanistan 1997 635.
# ℹ 1,694 more rows
starts_with()
, ends_with()
, contains()
와 같은 도우미 함수를 잘 활용하면 효율적으로 필요한 변수만을 선정할 수 있다.
# 이름이 "c"로 시작하는 변수들만 선택
gapminder |>
select(starts_with("c"))
# A tibble: 1,704 × 2
country continent
<fct> <fct>
1 Afghanistan Asia
2 Afghanistan Asia
3 Afghanistan Asia
4 Afghanistan Asia
5 Afghanistan Asia
6 Afghanistan Asia
7 Afghanistan Asia
8 Afghanistan Asia
9 Afghanistan Asia
10 Afghanistan Asia
# ℹ 1,694 more rows
1.3.2 mutate()
함수
기존의 열(변수)에 기반하여 새로운 변수를 생성한다. 열의 길이가 는다.
# 새롭게 정의한 gdp_billion 변수 추가
gapminder |>
mutate(
gdp_billion = gdpPercap * pop / 10^9
)
# A tibble: 1,704 × 7
country continent year lifeExp pop gdpPercap gdp_billion
<fct> <fct> <int> <dbl> <int> <dbl> <dbl>
1 Afghanistan Asia 1952 28.8 8425333 779. 6.57
2 Afghanistan Asia 1957 30.3 9240934 821. 7.59
3 Afghanistan Asia 1962 32.0 10267083 853. 8.76
4 Afghanistan Asia 1967 34.0 11537966 836. 9.65
5 Afghanistan Asia 1972 36.1 13079460 740. 9.68
6 Afghanistan Asia 1977 38.4 14880372 786. 11.7
7 Afghanistan Asia 1982 39.9 12881816 978. 12.6
8 Afghanistan Asia 1987 40.8 13867957 852. 11.8
9 Afghanistan Asia 1992 41.7 16317921 649. 10.6
10 Afghanistan Asia 1997 41.8 22227415 635. 14.1
# ℹ 1,694 more rows
여러개의 변수를 동시에 생성할 수 있다. row_number()
도우미 함수는 값에 순위를 부여하는 것이고, .keep = "used"
는 결과에 변수 생성에 동원된 변수만을 포함시키게 해 준다.
gapminder |>
filter(year == 2007) |> # year이 2007인 행만 선택
mutate(
gdpPercap_rank = row_number(gdpPercap), # gdpPercap에 순위 부여
lifeExp_highlow = lifeExp > 30, # lifeExp가 30을 넘으면 TRUE, 아니면 FALSE
.keep = "used" # 새로운 변수 생성에 사용한 변수들만 표시
)
# A tibble: 142 × 4
lifeExp gdpPercap gdpPercap_rank lifeExp_highlow
<dbl> <dbl> <int> <lgl>
1 43.8 975. 19 TRUE
2 76.4 5937. 70 TRUE
3 72.3 6223. 72 TRUE
4 42.7 4797. 64 TRUE
5 75.3 12779. 101 TRUE
6 81.2 34435. 130 TRUE
7 79.8 36126. 132 TRUE
8 75.6 29796. 122 TRUE
9 64.1 1391. 30 TRUE
10 79.4 33693. 128 TRUE
# ℹ 132 more rows
1.3.3 rename()
함수
변수의 이름을 바꾼다. 열의 길이에는 변화가 없다.
# 변수의 이름 변경
gapminder |>
rename(
gdp_percap = gdpPercap,
left_exp = lifeExp
)
# A tibble: 1,704 × 6
country continent year left_exp pop gdp_percap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Afghanistan Asia 1952 28.8 8425333 779.
2 Afghanistan Asia 1957 30.3 9240934 821.
3 Afghanistan Asia 1962 32.0 10267083 853.
4 Afghanistan Asia 1967 34.0 11537966 836.
5 Afghanistan Asia 1972 36.1 13079460 740.
6 Afghanistan Asia 1977 38.4 14880372 786.
7 Afghanistan Asia 1982 39.9 12881816 978.
8 Afghanistan Asia 1987 40.8 13867957 852.
9 Afghanistan Asia 1992 41.7 16317921 649.
10 Afghanistan Asia 1997 41.8 22227415 635.
# ℹ 1,694 more rows
패밀리 함수인 rename_with()
를 이용하면 다른 것도 가능하다.
# "l"로 시작하는 변수를 전부 소문자로 변경
gapminder |>
rename_with(
tolower, starts_with("l")
)
# A tibble: 1,704 × 6
country continent year lifeexp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Afghanistan Asia 1952 28.8 8425333 779.
2 Afghanistan Asia 1957 30.3 9240934 821.
3 Afghanistan Asia 1962 32.0 10267083 853.
4 Afghanistan Asia 1967 34.0 11537966 836.
5 Afghanistan Asia 1972 36.1 13079460 740.
6 Afghanistan Asia 1977 38.4 14880372 786.
7 Afghanistan Asia 1982 39.9 12881816 978.
8 Afghanistan Asia 1987 40.8 13867957 852.
9 Afghanistan Asia 1992 41.7 16317921 649.
10 Afghanistan Asia 1997 41.8 22227415 635.
# ℹ 1,694 more rows
1.3.4 relocate()
함수
변수의 위치를 바꾼다. 열의 길이에는 변화가 없다.
# year 변수의 위치를 continent 앞으로 이동
gapminder |>
relocate(year, continent)
# A tibble: 1,704 × 6
year continent country lifeExp pop gdpPercap
<int> <fct> <fct> <dbl> <int> <dbl>
1 1952 Asia Afghanistan 28.8 8425333 779.
2 1957 Asia Afghanistan 30.3 9240934 821.
3 1962 Asia Afghanistan 32.0 10267083 853.
4 1967 Asia Afghanistan 34.0 11537966 836.
5 1972 Asia Afghanistan 36.1 13079460 740.
6 1977 Asia Afghanistan 38.4 14880372 786.
7 1982 Asia Afghanistan 39.9 12881816 978.
8 1987 Asia Afghanistan 40.8 13867957 852.
9 1992 Asia Afghanistan 41.7 16317921 649.
10 1997 Asia Afghanistan 41.8 22227415 635.
# ℹ 1,694 more rows
.before
나 .after
아규먼트를 사용하여 해당 변수를 어떤 변수의 앞이나 뒤로 보낼 수 있다.
# pop 변수의 위치를 lifeExp 앞으로 이동
gapminder |>
relocate(pop, .before = lifeExp )
# A tibble: 1,704 × 6
country continent year pop lifeExp gdpPercap
<fct> <fct> <int> <int> <dbl> <dbl>
1 Afghanistan Asia 1952 8425333 28.8 779.
2 Afghanistan Asia 1957 9240934 30.3 821.
3 Afghanistan Asia 1962 10267083 32.0 853.
4 Afghanistan Asia 1967 11537966 34.0 836.
5 Afghanistan Asia 1972 13079460 36.1 740.
6 Afghanistan Asia 1977 14880372 38.4 786.
7 Afghanistan Asia 1982 12881816 39.9 978.
8 Afghanistan Asia 1987 13867957 40.8 852.
9 Afghanistan Asia 1992 16317921 41.7 649.
10 Afghanistan Asia 1997 22227415 41.8 635.
# ℹ 1,694 more rows
1.4 그룹 함수
1.4.1 group_by()
함수
특정 범주 열(변수)에 의거해 행을 분할한다. 행의 길이는 변하지 않는다.
하나의 범주 변수에 의거해 그룹화한다. 산출물을 보면 year
에 의거해 행이 12개의 그룹으로 나누어졌음이 나타나 있다(두 번째 줄: Group: year [12]).
# year을 기준으로 그룹화
gapminder |>
group_by(year)
# A tibble: 1,704 × 6
# Groups: year [12]
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Afghanistan Asia 1952 28.8 8425333 779.
2 Afghanistan Asia 1957 30.3 9240934 821.
3 Afghanistan Asia 1962 32.0 10267083 853.
4 Afghanistan Asia 1967 34.0 11537966 836.
5 Afghanistan Asia 1972 36.1 13079460 740.
6 Afghanistan Asia 1977 38.4 14880372 786.
7 Afghanistan Asia 1982 39.9 12881816 978.
8 Afghanistan Asia 1987 40.8 13867957 852.
9 Afghanistan Asia 1992 41.7 16317921 649.
10 Afghanistan Asia 1997 41.8 22227415 635.
# ℹ 1,694 more rows
두 개 이상의 범주 변수에 의거해 그룹화할 수도 있다.
# year, continent를 기준으로 그룹화
gapminder |>
group_by(year, continent)
# A tibble: 1,704 × 6
# Groups: year, continent [60]
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Afghanistan Asia 1952 28.8 8425333 779.
2 Afghanistan Asia 1957 30.3 9240934 821.
3 Afghanistan Asia 1962 32.0 10267083 853.
4 Afghanistan Asia 1967 34.0 11537966 836.
5 Afghanistan Asia 1972 36.1 13079460 740.
6 Afghanistan Asia 1977 38.4 14880372 786.
7 Afghanistan Asia 1982 39.9 12881816 978.
8 Afghanistan Asia 1987 40.8 13867957 852.
9 Afghanistan Asia 1992 41.7 16317921 649.
10 Afghanistan Asia 1997 41.8 22227415 635.
# ℹ 1,694 more rows
1.4.2 summarize()
함수
주어진 열(변수)에 대한 통계 요약값을 계산하고 그것으로 이루어진 새로운 데이터 프레임을 생성한다. 엄밀히 말해 기존 열(변수)을 변형한다기 보다는 기존 데이터 프레임으로부터 새로운 데이터 프레임을 생성한다고 볼 수 있다. summarize()
함수는 대부분의 경우 group_by()
함수와 함께 사용된다. 다음의 둘을 비교해 보라.
# 2007년 전체의 gdpPercap의 평균 계산
gapminder |>
filter(year == 2007) |> # year이 2007인 행만 선택
summarize(mean_gdpPercap = mean(gdpPercap)) # gdpPercap의 평균값 계산
# A tibble: 1 × 1
mean_gdpPercap
<dbl>
1 11680.
# 2007년 대륙별 gdpPercap의 평균 계산
gapminder |>
filter(year == 2007) |> # year이 2007인 행만 선택
group_by(continent) |> # continent를 기준으로 그룹화
summarize(mean_gdpPercap = mean(gdpPercap)) # gdpPercap의 평균값 계산
# A tibble: 5 × 2
continent mean_gdpPercap
<fct> <dbl>
1 Africa 3089.
2 Americas 11003.
3 Asia 12473.
4 Europe 25054.
5 Oceania 29810.
좀 더 복잡한 확장이 가능하다. 마지막의 n()
은 자동으로 생성되는 그룹별 빈도값이다.
# continent, year별로 다양한 통계값 산출
gapminder |>
group_by(continent, year) |> # continent, year을 기준으로 그룹화
summarize(
mean_gdpPercap = mean(gdpPercap), # gdpPercap의 평균값 계산
sd_gdpPercap = sd(gdpPercap), # gdpPercap의 표준편차 계산
mean_pop = mean(pop), # pop의 평균값 계산
sd_pop = sd(pop), # pop의 표준편차 계산
n = n() # 그룹에 포함된 행의 개수
)
# A tibble: 60 × 7
# Groups: continent [5]
continent year mean_gdpPercap sd_gdpPercap mean_pop sd_pop n
<fct> <int> <dbl> <dbl> <dbl> <dbl> <int>
1 Africa 1952 1253. 983. 4570010. 6317450. 52
2 Africa 1957 1385. 1135. 5093033. 7076042. 52
3 Africa 1962 1598. 1462. 5702247. 7957545. 52
4 Africa 1967 2050. 2848. 6447875. 8985505. 52
5 Africa 1972 2340. 3287. 7305376. 10130833. 52
6 Africa 1977 2586. 4142. 8328097. 11585184. 52
7 Africa 1982 2482. 3243. 9602857. 13456243. 52
8 Africa 1987 2283. 2567. 11054502. 15277484. 52
9 Africa 1992 2282. 2644. 12674645. 17562719. 52
10 Africa 1997 2379. 2821. 14304480. 19873013. 52
# ℹ 50 more rows
group_by()
와 arrange()
를 결합하는 경우, .by_group = TRUE
를 하면 그룹별로 행을 배열할 수 있다.
# year, continent 그룹별로 gdpPercap 내림차순 정렬
gapminder |>
group_by(year, continent) |> # year, continent를 기준으로 그룹화
arrange(desc(gdpPercap), .by_group = TRUE) # 그룹별로 gdpPercap 내림차순 정렬
# A tibble: 1,704 × 6
# Groups: year, continent [60]
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 South Africa Africa 1952 45.0 14264935 4725.
2 Gabon Africa 1952 37.0 420702 4293.
3 Angola Africa 1952 30.0 4232095 3521.
4 Reunion Africa 1952 52.7 257700 2719.
5 Djibouti Africa 1952 34.8 63149 2670.
6 Algeria Africa 1952 43.1 9279525 2449.
7 Namibia Africa 1952 41.7 485831 2424.
8 Libya Africa 1952 42.7 1019729 2388.
9 Congo, Rep. Africa 1952 42.1 854885 2126.
10 Mauritius Africa 1952 51.0 516556 1968.
# ℹ 1,694 more rows
.by_group = TRUE
를 사용하지 않은 경우
.by_group = TRUE
를 붙이지 않으면 그냥 arrange()
를 사용한 것과 같은 결과가 나온다.
# A tibble: 1,704 × 6
# Groups: year, continent [60]
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Kuwait Asia 1957 58.0 212846 113523.
2 Kuwait Asia 1972 67.7 841934 109348.
3 Kuwait Asia 1952 55.6 160000 108382.
4 Kuwait Asia 1962 60.5 358266 95458.
5 Kuwait Asia 1967 64.6 575003 80895.
6 Kuwait Asia 1977 69.3 1140357 59265.
7 Norway Europe 2007 80.2 4627926 49357.
8 Kuwait Asia 2007 77.6 2505559 47307.
9 Singapore Asia 2007 80.0 4553009 47143.
10 Norway Europe 2002 79.0 4535591 44684.
# ℹ 1,694 more rows
# A tibble: 1,704 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Kuwait Asia 1957 58.0 212846 113523.
2 Kuwait Asia 1972 67.7 841934 109348.
3 Kuwait Asia 1952 55.6 160000 108382.
4 Kuwait Asia 1962 60.5 358266 95458.
5 Kuwait Asia 1967 64.6 575003 80895.
6 Kuwait Asia 1977 69.3 1140357 59265.
7 Norway Europe 2007 80.2 4627926 49357.
8 Kuwait Asia 2007 77.6 2505559 47307.
9 Singapore Asia 2007 80.0 4553009 47143.
10 Norway Europe 2002 79.0 4535591 44684.
# ℹ 1,694 more rows
아래는 연도별/대륙별로 일인당 GDP가 가장 높은 국가를 추출한 것이다. 코드를 생각해 보라. Code를 누르면 답을 확인할 수 있다.
# A tibble: 60 × 6
# Groups: year, continent [60]
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 South Africa Africa 1952 45.0 14264935 4725.
2 United States Americas 1952 68.4 157553000 13990.
3 Kuwait Asia 1952 55.6 160000 108382.
4 Switzerland Europe 1952 69.6 4815000 14734.
5 New Zealand Oceania 1952 69.4 1994794 10557.
6 South Africa Africa 1957 48.0 16151549 5487.
7 United States Americas 1957 69.5 171984000 14847.
8 Kuwait Asia 1957 58.0 212846 113523.
9 Switzerland Europe 1957 70.6 5126000 17909.
10 New Zealand Oceania 1957 70.3 2229407 12247.
# ℹ 50 more rows
group_by()
함수가 한 번 적용되면, 그 뒤의 모든 오퍼레이션에 그룹 분할이 적용되기 때문에 예기치 못한 일이 발생할 수 있다. 이것을 회피하기 위해 두 가지 옵션이 있다. 첫번째 방법은 마지막에 upgroup()
함수를 첨가하는 것이다.
# 그룹화를 해제하고 year, continent별로 gdpPercap이 가장 높은 국가 선택
gapminder |>
group_by(year, continent) |> # year, continent를 기준으로 그룹화
slice_max(gdpPercap) |> # 그룹에서 gdpPercap이 가장 높은 행 선택
ungroup() # 그룹화 해제
# A tibble: 60 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 South Africa Africa 1952 45.0 14264935 4725.
2 United States Americas 1952 68.4 157553000 13990.
3 Kuwait Asia 1952 55.6 160000 108382.
4 Switzerland Europe 1952 69.6 4815000 14734.
5 New Zealand Oceania 1952 69.4 1994794 10557.
6 South Africa Africa 1957 48.0 16151549 5487.
7 United States Americas 1957 69.5 171984000 14847.
8 Kuwait Asia 1957 58.0 212846 113523.
9 Switzerland Europe 1957 70.6 5126000 17909.
10 New Zealand Oceania 1957 70.3 2229407 12247.
# ℹ 50 more rows
두 번째 방법은 group_by()
함수 대신 by
아규먼트를 사용하는 것이다. 결과가 달라보이겠지만 정렬의 차이일 뿐 동일하다.
# year, continent 기준으로 gdpPercap이 가장 높은 행 선택
gapminder |>
slice_max(gdpPercap, by = c(year, continent))
# A tibble: 60 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Kuwait Asia 1952 55.6 160000 108382.
2 Kuwait Asia 1957 58.0 212846 113523.
3 Kuwait Asia 1962 60.5 358266 95458.
4 Kuwait Asia 1967 64.6 575003 80895.
5 Kuwait Asia 1972 67.7 841934 109348.
6 Kuwait Asia 1977 69.3 1140357 59265.
7 Saudi Arabia Asia 1982 63.0 11254672 33693.
8 Kuwait Asia 1987 74.2 1891487 28118.
9 Kuwait Asia 1992 75.2 1418095 34933.
10 Kuwait Asia 1997 76.2 1765345 40301.
# ℹ 50 more rows
1.4.3 count()
함수
특정 범주 열(변수)에 의거한 빈도를 빠르게 계산해 준다.
# year, continent별 행 개수 계산
gapminder |>
count(year, continent)
# A tibble: 60 × 3
year continent n
<int> <fct> <int>
1 1952 Africa 52
2 1952 Americas 25
3 1952 Asia 33
4 1952 Europe 30
5 1952 Oceania 2
6 1957 Africa 52
7 1957 Americas 25
8 1957 Asia 33
9 1957 Europe 30
10 1957 Oceania 2
# ℹ 50 more rows
wt
아규먼트를 사용하면 빈도가 아니라 범주별 특정 변수의 합산값을 구할 수 있다.
# year, continent별 pop의 합산값 계산
gapminder |>
count(year, continent, wt = pop)
# A tibble: 60 × 3
year continent n
<int> <fct> <dbl>
1 1952 Africa 237640501
2 1952 Americas 345152446
3 1952 Asia 1395357351
4 1952 Europe 418120846
5 1952 Oceania 10686006
6 1957 Africa 264837738
7 1957 Americas 386953916
8 1957 Asia 1562780599
9 1957 Europe 437890351
10 1957 Oceania 11941976
# ℹ 50 more rows
위의 두 개를 한 번에 실행할 수 있다.
gapminder |>
group_by(year, continent) |> # year, continent를 기준으로 그룹화
summarize(
n = n(), # 그룹별 행 개수 계산
sum_pop = sum(pop) # 그룹별 pop의 합산값 계산
)
# A tibble: 60 × 4
# Groups: year [12]
year continent n sum_pop
<int> <fct> <int> <dbl>
1 1952 Africa 52 237640501
2 1952 Americas 25 345152446
3 1952 Asia 33 1395357351
4 1952 Europe 30 418120846
5 1952 Oceania 2 10686006
6 1957 Africa 52 264837738
7 1957 Americas 25 386953916
8 1957 Asia 33 1562780599
9 1957 Europe 30 437890351
10 1957 Oceania 2 11941976
# ℹ 50 more rows
1.4.4 across()
함수
다수의 열(변수)에 동일한 함수를 적용할 수 있다.
# A tibble: 1,704 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Afghanistan Asia 1952 29 8425333 779
2 Afghanistan Asia 1957 30 9240934 821
3 Afghanistan Asia 1962 32 10267083 853
4 Afghanistan Asia 1967 34 11537966 836
5 Afghanistan Asia 1972 36 13079460 740
6 Afghanistan Asia 1977 38 14880372 786
7 Afghanistan Asia 1982 40 12881816 978
8 Afghanistan Asia 1987 41 13867957 852
9 Afghanistan Asia 1992 42 16317921 649
10 Afghanistan Asia 1997 42 22227415 635
# ℹ 1,694 more rows
이것은 다음과 동일하다.
gapminder |>
mutate(
lifeExp = round(lifeExp), # lifeExp를 반올림한 새로운 변수 생성
gdpPercap = round(gdpPercap) # gdpPercap을 반올림한 새로운 변수 생성
)
# A tibble: 1,704 × 6
country continent year lifeExp pop gdpPercap
<fct> <fct> <int> <dbl> <int> <dbl>
1 Afghanistan Asia 1952 29 8425333 779
2 Afghanistan Asia 1957 30 9240934 821
3 Afghanistan Asia 1962 32 10267083 853
4 Afghanistan Asia 1967 34 11537966 836
5 Afghanistan Asia 1972 36 13079460 740
6 Afghanistan Asia 1977 38 14880372 786
7 Afghanistan Asia 1982 40 12881816 978
8 Afghanistan Asia 1987 41 13867957 852
9 Afghanistan Asia 1992 42 16317921 649
10 Afghanistan Asia 1997 42 22227415 635
# ℹ 1,694 more rows
새롭게 생성한 변수가 기존 변수와 이름이 같은 경우 기존 변수를 대체한다.
summarize()
함수와 결합하여 선택된 변수에 특정 함수를 적용하고 그 결과의 이름을 변수명과 함수명을 사용하여 부여할 수 있다.
gapminder |>
group_by(year, continent) |> # year, continent를 기준으로 그룹화
summarize(across(c(lifeExp, gdpPercap), mean, # lifeExp와 gdpPercap의 평균값 계산
.names = "mean_{.col}")) # 새롭게 생성된 변수의 이름을 "mean_기존 이름"으로 설정
# A tibble: 60 × 4
# Groups: year [12]
year continent mean_lifeExp mean_gdpPercap
<int> <fct> <dbl> <dbl>
1 1952 Africa 39.1 1253.
2 1952 Americas 53.3 4079.
3 1952 Asia 46.3 5195.
4 1952 Europe 64.4 5661.
5 1952 Oceania 69.3 10298.
6 1957 Africa 41.3 1385.
7 1957 Americas 56.0 4616.
8 1957 Asia 49.3 5788.
9 1957 Europe 66.7 6963.
10 1957 Oceania 70.3 11599.
# ℹ 50 more rows
1.4.5 c_across()
함수
group_by()
함수와 across()
함수가 결합하는 것과 정반대로, rowwise()
함수와 c_across()
함수를 결합하며, 행별 통계값을 산출할 수 있다. 물론 여기서 sd 값은 아무런 의미가 없다.
gapminder |>
rowwise() |> # 행별로 그룹화
mutate(
sd = sd(c_across(where(is.numeric))) # 각 행에서 숫자인 값들의 표준편차 계산
)
# A tibble: 1,704 × 7
# Rowwise:
country continent year lifeExp pop gdpPercap sd
<fct> <fct> <int> <dbl> <int> <dbl> <dbl>
1 Afghanistan Asia 1952 28.8 8425333 779. 4212207.
2 Afghanistan Asia 1957 30.3 9240934 821. 4619999.
3 Afghanistan Asia 1962 32.0 10267083 853. 5133067.
4 Afghanistan Asia 1967 34.0 11537966 836. 5768510.
5 Afghanistan Asia 1972 36.1 13079460 740. 6539272.
6 Afghanistan Asia 1977 38.4 14880372 786. 7439719.
7 Afghanistan Asia 1982 39.9 12881816 978. 6440408.
8 Afghanistan Asia 1987 40.8 13867957 852. 6933499.
9 Afghanistan Asia 1992 41.7 16317921 649. 8158513.
10 Afghanistan Asia 1997 41.8 22227415 635. 11113262.
# ℹ 1,694 more rows
2 데이터 시각화
실습을 위해 ggplot2
패키지 속에 포함되어 있는 mpg
데이터와 diamonds 데이터를 사용한다. 각 데이터에서 눈여겨 볼 변수는 아래와 같다.
-
mpg
displ
: 배기량(displacement)class
: 자동차 유형(compact/midsize/suv/2seater/minivan/pickup/subcompact)hwy
: 고속도로(highway) 연비
-
diamonds
price
: 가격carat
: 캐럿color
: 다이아몬드 색깔clarity
: 투명도cut
: 가공의 품질
2.1 핵심 레이어: 심미성과 기하
이 실습은 R로 데이터사이언스를 하는 과정 중 데이터 시각화하기(visualizing)를 다룬다. 데이터 시각화하기는 tidyverse
의 핵심 패키지 중의 하나인 ggplot2
에서 제공된다.
ggplot2의 gg
가 ’그래프의 문법(grammar of graphic)’을 의미하는 것에서 알 수 있는 것처럼, ggplot2는 그래프 제작의 일반 원리를 정교하게 구현하기 위해 만들어졌다. 아래 그림에서 볼 수 있듯, 모든 그래프는 8개의 주요 구성요소로 이루어져 있고, ggplot2는 각각의 구성요소를 마치 레이어(layer)를 쌓는 것과 같은 방식으로 구현한다(+
사인을 이용).
이 8개 구성요소 중 가장 중요한 것은 ‘심미성(aesthetics)’ 혹은 ‘심미성 매핑(aesthetic mapping)’와 ’기하(geometries)’ 혹은 ’기하 객체(geometric objects)’이다. 기하가 그래프의 전체 구조 혹은 형식을 규정하는 것이라면, 심미성은 기하의 외견을 규정한다. 결국 기하는 그래프의 유형(예: 막대 그래프, 산포도 등)과 관련되고, 심미성은 그래프의 시각적 속성(예: x축, y축, 컬러, 크기, 모양 등)과 관련된다. 이 두 가지는 독립적인 요소이지만, 어느 정도는 관련되어 있기도 하다. 모든 기하가 모든 심미성과 결합할 수 있는 것은 아니다. 특정한 기하는 오로지 특정한 심미성과만 결합한다. 예를 들어 포인트 기하 객체(geom_point()
)는 크기(size
) 심미성과 관련되지만, 라인 기하 객체(geom_line()
)는 크기 심미성과는 관련되지 않고 라인폭(linewidth
) 심미성과만 관련되는 식이다.
2.1.1 기초 예제
그래프를 그리기 위해 반드시 필요한 것은 데이터, 심미성, 기하이다. 이들을 차례로 하나씩 추가해본다.
Figure 1 를 보면, 빈 화면만 출력되는 것을 볼 수 있다. 데이터만 올라왔으므로, 그릴 수 있는 것이 없다. Figure 2 에서는 x축과 y축이 나타났다. 그러나 이 재료를 가지고 무슨 그래프를 그릴지는 지정하지 않았으므로 아무 그래프도 나타나지 않는다. Figure 3 에서야 비로소 그래프가 나타나는데, 이는 어떤 데이터로부터 어떤 변수를 사용할지, 그리고 그것을 어떤 방식으로 그릴지를 모두 지정해주었기 때문이다.
# 데이터만 추가
ggplot(data=mpg)
ggplot(data=mpg, aes(x=displ, y=hwy)) +
geom_point()
2.1.2 심미성 매핑
심미성 매핑이란 다양한 시각적 속성 혹은 재료를 그래프에 적용 혹은 부여하는 과정을 의미한다. displ
과 hwy
의 관계가 class
에 따라 어떻게 달라지는지를 시각화한다. 다음의 두 그래프를 비교해 본다.
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
geom_point()
ggplot(mpg, aes(x = displ, y = hwy, shape = class)) +
geom_point()
Figure 4 과 Figure 5 중 어느 것이 더 효과적인 시각화라고 생각하는가? 컬러(color
)와 형태(shape
)라는 심미성 요소 외에 크기(size
)와 투명도(alpha
) 요소를 동일한 데이터에 적용해 본다.
ggplot(mpg, aes(x = displ, y = hwy, size = class)) +
geom_point()
ggplot(mpg, aes(x = displ, y = hwy, alpha = class)) +
geom_point()
크기와 투명도는 양적인 차이를 나타내는데 적합한 심미성이기 때문에 class
라는 정성적인 범주의 차이를 보여주는데는 적합하지 않다. 심미성 부여에서 가장 중요한 것은 결국 얼마나 적절한 심미성 요소, 혹은 시각 변수(visual variables)를 선택하느냐에 달려 있다.
2.1.3 기하 객체
Figure 8 와 Figure 9 이 다르게 보이는 것은 기하 객체가 하나는 포인트(point
)이고 다른 하나는 완만한 선(smooth
)이기 때문이다.
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point()
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_smooth()
Figure 4 과 Figure 9 두 개를 결합해 본다.
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
geom_point() +
geom_smooth()
원하는 것이 아니다. 왜 이런 결과가 나왔으며, 어떻게 하면 원하는 것을 얻을 수 있을지 생각해 본다.
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = class)) +
geom_smooth()
두 결과의 차이는 color
심미성을 글로벌하게 적용하느냐 로컬하게 적용하느냐(포인트 기하에만 적용)에 달린 것이다. 글로벌한 심미성은 ggplot()
속에서 설정하고, 국지적인 심미성은 개별 기하(geom_point()
) 속에서 설정한다. 매우 중요한 사항이니 꼭 기억하도록 한다.
다양한 기하 객체는 동일한 데이터를 다양한 방식으로 탐색할 수 있게 해준다. 다음의 세가지 기하 객체는 탐색적 데이터 분석에서 널리 사용되는 것이다.
ggplot(mpg, aes(x = hwy)) +
geom_histogram(binwidth = 2)
ggplot(mpg, aes(x = hwy)) +
geom_density()
ggplot(mpg, aes(x = hwy)) +
geom_boxplot()
2.2 다른 레이어
2.2.1 스케일
스케일(scales)은 심미성이 구체적으로 어떻게 구현될지를 결정한다. 예를 들어 color 심미성이 적용되었다 하더라도 어떤 색상이 선정되어 어떻게 배열되는지에 따라 최종 그래프의 모습은 매우 달라질 수 있다. 그래프를 다시 나타낸다. 스케일이 어느 부분에 어떻게 적용되었는지 생각해 본다.
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
geom_point()
Figure 15 은 아래에서 보는 것처럼, ggplot2
가 자동적으로 적용한 세 가지의 스케일 설정에 의거해 만들어진 것이다.
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
geom_point() +
scale_x_continuous() +
scale_y_continuous() +
scale_color_discrete()
수정하여 다음과 같이 적용할 수 있다. scale
함수의 아규먼트가 어떤 역할을 하는지 생각해 본다.
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
geom_point() +
scale_x_continuous(labels = NULL) +
scale_y_continuous(breaks = seq(15, 40, by = 5)) +
scale_color_brewer(palette = "Set1", labels = c("4" = "4-wheel", "f" = "front", "r" = "rear"))
scale_color_brewer()
함수는 ColorBrewer 컬러 스케일을 사용한 것인데 익히고 있으면 많은 도움이 된다. 살펴보면 양적인 변수에 적용하기 좋은 팔레트가 있고, 질적인 변수에 적용하기 좋은 팔레트도 있다. 한번 마음에 드는 팔레트를 골라보자.
par(mar=c(0.1, 3, 0.1, 1))
display.brewer.all()
한편, 내가 원하는 색상을 골라 직접 지정하는 방법도 있다. scale_color_brewer()
대신 scale_color_manual()
함수를 사용하면 된다. 또한 RGB 색상에 대한 html 코드를 사용해도 되고, R에서 부여한 657개의 이름 중에서 골라 사용해도 된다. 색상 이름 및 html 코드는 다음 사이트를 참고하라.
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
geom_point() +
scale_x_continuous(labels = NULL) +
scale_y_continuous(breaks = seq(15, 40, by = 5)) +
scale_color_manual(values = c("sienna1", "slateblue4", "#698B22"))
2.2.2 패싯
패싯(facets) 레이어는 다면생성(faceting) 과정을 통해 하나의 플롯을 여러개의 하위 플롯으로 쪼갬으로서 생성된다.
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point() +
facet_wrap(~cyl)
두 개의 변수에 의거해 패싯을 생성할 수도 있다.
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point() +
facet_grid(drv ~ cyl)
2.2.3 통계적 변환
어떤 시각화 과정은 필연적으로 통계적 변환(statistical transformation)을 수반한다.
after_stat()
이라고 하는 도우미 함수를 사용하면, 이 그래프를 절대 빈도가 아닌 상대 빈도 그래프로 변환할 수 있다. 이 역시 통계적 변환 과정이 숨어 있는 것이다.
ggplot(diamonds, aes(x = cut, y = after_stat(prop), group = 1)) +
geom_bar()
geom_bar()
함수는 자동으로 통계적 변환을 한 후 결과를 반환한다. 그래서 y축을 지정하지 않아도 된다. 반면 geom_col()
함수는 마찬가지로 막대그래프이지만, x축과 그에 상응하는 y축의 값을 바탕으로 그래프를 생성한다. 아래의 두 코드를 살펴보고 결과를 비교해보자. geom_bar()
의 통계적 변환이 무엇을 한 것인지, 두 함수의 차이가 무엇이지 이해할 수 있을 것이다. 참고로 두 번째 코드는 지난 실습 때 다룬 count()
함수를 활용한 것이다. 다른 코드이지만 동일한 결과가 출력됨됨을 알 수 있다.
막대 그래프에 심미성을 가미하고, position
아규먼트를 통한 위치 조정(position adjustment)을 시도한다.
기하 객체에 색상을 지정하고 싶을 때, 0차원(point
)과 1차원(line
) 객체에는 color
라는 심미성을 적용하지만, 막대 그래프와 같은 2차원(area
) 객체에는 fill
이라는 심미성을 적용한다. 자주 혼돈이 되는 부분이다.
위치 조정을 위해 position
아규먼트를 사용하는데, 네 가지 옵션이 있다.
position = "stack"
position = "identity"
position = "dodge"
position = "fill"
Figure 21 에는 디폴트로 position = "stack"
이 적용된 것이다. Figure 22 는 position = "dodge"
를 적용한 것이다 . 나머지 옵션도 적용해보고 차이가 무엇인지 알아본다.
position
아규먼트에 따른 차이는 아래의 그래프가 잘 보여준다. patchwork
도 활용했다.
g1 <- ggplot(mpg, aes(x = drv, fill = class)) +
geom_bar(position = "stack") +
labs(title = "'stack' graph")
g2 <- ggplot(mpg, aes(x = drv, fill = class)) +
geom_bar(position = "dodge") +
labs(title = "'dodge' graph")
g3 <- ggplot(mpg, aes(x = drv, fill = class)) +
geom_bar(position = "fill") +
labs(title = "'fill' graph")
g4 <- ggplot(mpg, aes(x = drv, fill = class)) +
geom_bar(position = "identity") +
labs(title = "'identity' graph")
g1+g2+g3+g4 +
plot_annotation(
title = "How does position argument work?",
subtitle = "Graph differences by position argument"
)
2.2.4 좌표
좌표(coordinates) 레이어 혹은 좌표계(coordinate systems)는 그래픽 요소들의 위치 결정에 기준이 되는 준거체계이다. 특히 두 가지가 함수가 유용하다. coord_flip()
함수는 축을 전환한다.
ggplot(mpg, aes(x = drv, fill = class)) +
geom_bar(position = "fill") +
coord_flip()
coord_fixed()
함수는 두 축의 스케일을 절대화하여 동일하게 적용한다. 아규먼트로 x축 한 단위 대비 y축 한 단위의 비(y/x)를 받으며, 생략할 경우 디폴트로 1을 지정한다. 무슨 의미인지 알아본다.
ggplot(mpg, aes(cty, hwy)) +
geom_point() +
coord_fixed()
coord_fixed()
함수를 사용할까?
coord_fixed()
를 사용하지 않아도 ggplot
은 적당한 비율을 찾아 그래프를 그려준다. 그러나 간혹 사용자가 원하는 가로-세로 비율이 있을 때가 있다. 예를 들어, 우리나라가 동고서저의 지형임을 보여주는 그래프를 그려보자.
# 비율 지정 안하면?
ggplot(data, aes(x=x, y=y)) +
geom_point()+
geom_line()+
labs(x="서울-강릉(km)", y="고도(m)")
비율을 지정하지 않으니 조금 이상하다. 시각적 효과를 위해서, 가로 한 단위와 세로 한 단위의 비율을 적절히 맞춰보자.
# 적정 비율 지정하기
ggplot(data, aes(x=x, y=y)) +
geom_point()+
geom_line()+
labs(x="서울-강릉(km)", y="고도(m)") +
coord_fixed(ratio = 0.02)
아까보다 조금 더 가독성이 좋아짐을 확인할 수 있다.
2.2.5 테마
디폴트인 회색빛 배경이 마음에 들지 않았다면 Figure 25 처럼 흑백 테마(theme_bw()
)를 적용할 수도 있다. 다른 테마도 적용해 보고 그 차이를 알아본다.
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = class)) +
geom_smooth(se = FALSE) +
theme_bw()
이렇게 한꺼번에 그래프의 외관을 바꿀 수도 있지만 theme()
함수를 통해 그래프의 개별 요소 하나씩을 모두 수정할 수 있다. 어떤 요소를 바꿀 수 있는지 다음을 참고한다.
Figure 26 는 몇 가지 요소를 수정한 사례이다.
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
geom_point() +
labs(
title = "Larger engine sizes tend to have lower fuel economy",
caption = "Source: https://fueleconomy.gov."
) +
theme(
legend.position = c(0.6, 0.7),
legend.direction = "horizontal",
plot.title = element_text(face = "bold"),
plot.title.position = "plot",
plot.caption.position = "plot",
plot.caption = element_text(hjust = 0)
)
2.3 기타 사항
2.3.1 라벨과 주석
lab()
함수를 활용하면 그래프의 다양한 종류의 라벨을 설정할 수 있다.
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = class)) +
geom_smooth(se = FALSE) +
labs(
x = "Engine displacement (L)",
y = "Highway fuel economy (mpg)",
color = "Car type",
title = "Fuel efficiency generally decreases with engine size",
subtitle = "Two seaters (sports cars) are an exception because of their light weight",
caption = "Data from fueleconomy.gov"
)
기하 함수인 geom_text()
혹은 geom_label()
를 통해 그래프 속에 텍스트를 삽입할 수 있다. 주석이 겹치는 것을 방지하기 위해 ggrepel
패키지가 유용하게 사용될 수 있다.
ggplot(mpg, aes(displ, hwy)) +
geom_point(colour = "red") +
geom_label_repel(data = mpg |> slice_sample(prop = 0.1), aes(label = class))
2.3.2 레이아웃
레이아웃(layout)은 복수의 그래프를 적절히 배치하여 하나의 그래픽으로 융합하는 과정을 의미한다. 수 많은 ggplot2
의 확장 패키지(ggplot2 extensions) 중 하나이 patchwork
패키지를 활용할 수 있다.
p1 <- ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point() +
labs(title = "Plot 1")
p2 <- ggplot(mpg, aes(x = drv, y = hwy)) +
geom_boxplot() +
labs(title = "Plot 2")
p1 + p2
patchwork()
더 살펴보기
patchwork()
패키지는 그래프의 배치를 적용하는데 매우 유용하다. 좌우배치를 하되 자동으로 줄넘김을 원한다면 ‘A+B’, 무조건 좌우배치를 원할 때는 ‘A|B’, 상하배치를 원하다면 ’A/B’의 형식을 사용하면 된다. 매우 직관적이다. 위에서 position
아규먼트를 공부할 때 사용한 코드를 재사용해보자.
g1+g2+g3+g4
(g1+g3+g4)/g2
2.3.3 그래프의 저장
두 가지 방식이 있다.
첫 번째 방식은 Output 창의 Plots 탭에 있는 Export 버을 이용하는 것이다. 다양한 그래픽 포멧 뿐만 아니라 pdf 형식으로도 저장할 수 있다.
두 번째 방식은 ggplot2
의 ggsave()
함수를 이용하는 것이다. 결과물의 폰트 크기, 가로세로비, 해상도 등을 종합적으로 고려하여 최적의 세팅값을 찾아야 한다. 자신의 디바이스에 따라 동일한 세팅값이 다른 결과를 산출할 수도 있다.
my_plot <- ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
geom_point() +
labs(
title = "Larger engine sizes tend to have lower fuel economy",
caption = "Source: https://fueleconomy.gov."
) +
theme(
legend.position = c(0.6, 0.7),
legend.direction = "horizontal",
plot.title = element_text(face = "bold"),
plot.title.position = "plot",
plot.caption.position = "plot",
plot.caption = element_text(hjust = 0)
)
ggsave(filename = "my_plot.png", plot = my_plot, width = 8, height = 8 * 0.618, dpi = 600)