사용데이터 : https://2stndard.tistory.com/68
lubridate와 tsibble를 사용하는 기간별 합계값 구하기 - 주별 데이터
이전 포스트에서는 lubridate
와 zoo
를 사용하여 일간 데이터를 월간 데이터로 변환하는 방법을 알아보았다. 앞서도 언급했지만 우리가 사용하는 데이터는 주로 숫자나 문자로 이루어져 있고 대량의 데이터가 저장되어 있는 DB나 다른 데이터 소스에서 데이터를 추출할 때는 csv 파일이나 엑셀 파일 등으로 추출하고 R에서 불러들이는 것이 일반적인데 이 경우 흔히 날짜 데이터를 문자열 형태로 불러 읽어들이는 경우도 많다. 앞선 포스트에서와 같이 월별 데이터로 변환할 때는 문자열 형태로 설정된 날짜 데이터도 이 문자열을 잘 다루면 연별, 월별로 그룹화하여 변환하는 것이 가능하다. 하지만 주별 데이터로 변환하는 것은 문자열 형태의 날짜 데이터에서는 매우 어렵다. 그렇다면 주별 데이터는 어떻게 변환할 것인가?
주별 데이터도 앞선 월별 데이터와 거의 유사한 방식으로 전환이 가능하다.
주별 데이터의 변환에도 앞서 사용했던 코로나19의 일별 데이터인 ’df_covid19’를 사용하는데 주별 데이터는 좀 많으니 다음과 같이 정제하여 사용하도록 하겠다.
df_covid19_by_period <- df_covid19 |>
## 한국 데이터와 각 대륙별 데이터만을 필터링
filter(iso_code %in% c('KOR', 'OWID_ASI', 'OWID_EUR', 'OWID_OCE', 'OWID_NAM', 'OWID_SAM', 'OWID_AFR')) |>
## 읽은 데이터의 마지막 데이터에서 100일전 데이터까지 필터링
filter(date >= as.Date('2021-06-01')) |>
## 국가명을 한글로 변환
mutate(location = case_when(
location == 'South Korea' ~ '한국',
location == 'Asia' ~ '아시아',
location == 'Europe' ~ '유럽',
location == 'Oceania' ~ '오세아니아',
location == 'North America' ~ '북미',
location == 'South America' ~ '남미',
location == 'Africa' ~ '아프리카')) |>
## 국가 이름의 순서를 설정
mutate(location = fct_relevel(location, '한국', '아시아', '유럽', '북미', '남미', '아프리카', '오세아니아')) |>
## 날짜로 정렬
arrange(date)
head(df_covid19_by_period, 10)
## # A tibble: 10 x 67
## iso_code continent location date total_cases new_cases new_cases_smoot~
## <chr> <chr> <fct> <date> <dbl> <dbl> <dbl>
## 1 OWID_AFR <NA> 아프리카 2021-06-01 4850455 10120 11355.
## 2 OWID_ASI <NA> 아시아 2021-06-01 51481216 206374 242658.
## 3 OWID_EUR <NA> 유럽 2021-06-01 47255809 47249 52319
## 4 OWID_NAM <NA> 북미 2021-06-01 39073831 37619 30353.
## 5 OWID_OCE <NA> 오세아~ 2021-06-01 68669 43 145.
## 6 OWID_SAM <NA> 남미 2021-06-01 28957718 158438 140167
## 7 KOR Asia 한국 2021-06-01 141476 677 542
## 8 OWID_AFR <NA> 아프리카 2021-06-02 4864277 13822 11300
## 9 OWID_ASI <NA> 아시아 2021-06-02 51693192 211976 231289.
## 10 OWID_EUR <NA> 유럽 2021-06-02 47300174 44365 50056
## # ... with 60 more variables: total_deaths <dbl>, new_deaths <dbl>,
## # new_deaths_smoothed <dbl>, total_cases_per_million <dbl>,
## # new_cases_per_million <dbl>, new_cases_smoothed_per_million <dbl>,
## # total_deaths_per_million <dbl>, new_deaths_per_million <dbl>,
## # new_deaths_smoothed_per_million <dbl>, reproduction_rate <dbl>,
## # icu_patients <dbl>, icu_patients_per_million <dbl>, hosp_patients <dbl>,
## # hosp_patients_per_million <dbl>, weekly_icu_admissions <dbl>, ...
앞선 포스트에서는 월별 합계를 구했지만 이번에는 주단위로 평균값을 구해보도록 하겠다.
lubridate의 year(), week()를 사용
’date’형의 열을 주별로 그룹화하기 위해서는 lubridate
의 week()
를 사용할 수 있다. week()
는 매개변수로 지정된 벡터의 해당 년도 주차 수를 반환하는 함수이다. 하지만 week()
만을 사용하면 매년 같은 주차 데이터들은 같은 주차 수를 반환하기 때문에 주차의 시계열적 변화를 보기 위해서는 반드시 년을 반환하는 year()
를 같이 사용해주어야 한다. ’df_covid19_by_period’에서 연별, 주차별 한국의 신규확진자의 합은 다음과 같이 구할 수 있다.
library(lubridate)
df_covid19_by_period |>
group_by(년 = year(df_covid19_by_period$date), 주 = week(df_covid19_by_period$date), location) |>
summarise(신규확진자수 = mean(new_cases, na.rm = T)) |>
filter(location == '한국')
## # A tibble: 56 x 4
## # Groups: 년, 주 [56]
## 년 주 location 신규확진자수
## <dbl> <dbl> <fct> <dbl>
## 1 2021 22 한국 684.
## 2 2021 23 한국 572.
## 3 2021 24 한국 483.
## 4 2021 25 한국 507.
## 5 2021 26 한국 680
## 6 2021 27 한국 971.
## 7 2021 28 한국 1386
## 8 2021 29 한국 1527.
## 9 2021 30 한국 1582.
## 10 2021 31 한국 1514.
## # ... with 46 more rows
이 중에 한국의 월별 데이터를 선 그래프로 그린다면 다음과 같이 그릴 수 있겠다. 여기서 하나 주의할 것은 앞서 사용한 year()
와 week()
는 결과값이 문자열로 리턴된다는 것이다. 그래서 paste0()
를 사용하면 앞서 언급한 대로 1주, 10주, 11주, 12주, 2주와 같이 나타난다.
df_covid19_by_period |>
group_by(년 = year(df_covid19_by_period$date), 주 = week(df_covid19_by_period$date), location) |>
summarise(신규확진자수 = mean(new_cases, na.rm = T)) |>
filter(location == '한국') |>
ggplot(aes(x = paste0(년, '-', 주), y = 신규확진자수)) +
geom_line(aes(group = location)) +
theme(axis.text.x = element_text(angle = 90)) +
labs(x = '연월')
이러한 현상을 방지하기 위해서는 1~9주차에 해당하는 주차 수를 두 자리 정수 형태로 바꾸어 준다. 이를 위해서 sprintf()
를 사용하는데 이 함수는 원래 C언어에서 사용되는 함수로 R에서도 지원된다. 이 방법은 앞선 월간 데이터에서도 사용될 수 있지만 월간 데이터에서는 ‘Date’ 형으로 전환해서도 사용이 가능하다.
df_covid19_by_period |>
group_by(년 = year(df_covid19_by_period$date), 주 = week(df_covid19_by_period$date), location) |>
summarise(신규확진자수 = mean(new_cases, na.rm = T)) |>
filter(location == '한국') |>
mutate(주 = sprintf('%02d', 주)) |>
ggplot(aes(x = paste0(년, '-', 주), y = 신규확진자수)) +
geom_line(aes(group = location)) +
theme(axis.text.x = element_text(angle = 90)) +
labs(x = '연월')
lubridate의 floor_date()를 사용
앞선 예에서 year()
와 week()
를 사용하면 문자열이 반환되고 이를 다시 적절히 변환하여 사용해야 한다는 불편함이 있다. 이보다는 앞서 사용했던 floor_date()
를 사용해서 주간 단위로 그룹화하고 이에 대해 합계를 적용하면 앞의 예보다는 다소 코드가 쉬워질 수 있다.
floor_date()
는 주어진 시간 주기에 맞는 마지막 날을 리턴하는 함수로 이 날짜를 기준으로 그룹화하면 주 단위로 연산이 가능하다. 앞서에서는 월 단위로 그룹화하기 위해 매월 말일 단위로 그룹화하기 위해 ‘month’ 매개변수를 주었고 주 단위로 그룹화하기 위해서는 ‘week’ 매개변수를 설정한다.
df_covid19_by_period |>
group_by(연월 = floor_date(date, 'week'), location) |>
summarise(신규확진자수 = mean(new_cases, na.rm = T)) |>
filter(location == '한국')
## # A tibble: 55 x 3
## # Groups: 연월 [55]
## 연월 location 신규확진자수
## <date> <fct> <dbl>
## 1 2021-05-30 한국 671.
## 2 2021-06-06 한국 532.
## 3 2021-06-13 한국 468.
## 4 2021-06-20 한국 560.
## 5 2021-06-27 한국 716.
## 6 2021-07-04 한국 1137.
## 7 2021-07-11 한국 1415
## 8 2021-07-18 한국 1557.
## 9 2021-07-25 한국 1563.
## 10 2021-08-01 한국 1596.
## # ... with 45 more rows
이 데이터를 사용하여 선 그래프를 다음과 같이 그릴 수 있다. 다음에서는 date_labels
의 월 포맷을 ’%W’로 설정함으로써 주차 수를 표기하였다.
df_covid19_by_period |>
group_by(연월 = floor_date(date, 'month'), location) |>
summarise(신규확진자수 = mean(new_cases, na.rm = T)) |>
filter(location == '한국') |>
ggplot(aes(x = 연월, y = 신규확진자수)) +
geom_line(aes(group = location)) +
scale_x_date(date_breaks = '2 weeks', date_labels = '%y년 %W주') +
scale_y_continuous(labels = scales::comma) +
theme(axis.text.x = element_text(angle = 90))
tsibble의 yearmonth()를 사용
앞의 두 예를 보면 주별 데이터를 만드는데 lubridate
패키지의 함수들을 사용하였다. lubridate
는 R에서 시간 단위 연산에 매우 훌륭한 패키지임은 두말할 나위없지만 그 외에도 많이 사용되는 패키지들이 있다. 그중 최근 많이 사용되는 패키지가 tsibble
이다. 이 tsibble
패키지에서 제공하는 yearweek()
를 사용하면 연도와 주수를 반환하기 때문에 주단위로 연산하는데 매우 편리하게 사용할 수 있다. 또 yearmonth()
를 사용하면 월간 데이터도 쉽게 산출이 가능하다.
if (!require(tsibble)) {
install.packages('tsibble')
library(tsibble)
}
df_covid19_by_period |>
group_by(연월 = yearweek(date), location) |>
summarise(신규확진자수 = mean(new_cases, na.rm = T)) |>
filter(location == '한국')
## # A tibble: 55 x 3
## # Groups: 연월 [55]
## 연월 location 신규확진자수
## <week> <fct> <dbl>
## 1 2021 W22 한국 640.
## 2 2021 W23 한국 519.
## 3 2021 W24 한국 462.
## 4 2021 W25 한국 581.
## 5 2021 W26 한국 746.
## 6 2021 W27 한국 1193
## 7 2021 W28 한국 1437.
## 8 2021 W29 한국 1566.
## 9 2021 W30 한국 1548
## 10 2021 W31 한국 1635.
## # ... with 45 more rows
위의 데이터를 사용하여 선 그래프를 다음과 같이 그릴 수 있다. 다만 yearweek()
의 결과는 ‘Date’ 형이 아니기 때문에 ggplot2
에서 제공하는 scale_x_date()
를 사용할 수 없고 tsibble
패키지에서 제공하는 scales_x_yearweek()
을 사용해야 한다.
df_covid19_by_period |>
group_by(연월 = yearweek(date), location) |>
summarise(신규확진자수 = mean(new_cases, na.rm = T)) |>
filter(location == '한국') |>
ggplot(aes(x = 연월, y = 신규확진자수)) +
geom_line(aes(group = location)) +
scale_x_yearweek(date_breaks = '2 weeks', date_labels = '%y년 %W주') +
scale_y_continuous(labels = scales::comma) +
theme(axis.text.x = element_text(angle = 90))
'데이터 전처리' 카테고리의 다른 글
누적합과 누적평균 in R (0) | 2022.06.26 |
---|---|
열 이름 바꾸기 in R (0) | 2022.06.21 |
일별 데이터를 월별 데이터로 만들기 (0) | 2022.06.16 |
데이터프레임 합치기(Merge) in R (0) | 2022.06.12 |
특정 조건 행의 데이터만 바꾸기 (0) | 2022.06.11 |
댓글