R는 마이크로소프트(MS) 엑셀보다 데이터를 더 잘 처리합니다.
특히 해들리 위컴 박사가 개발한 dplyr 패키지와 함께라면 더더욱 그렇습니다.
이번 포스트에서는 프로야구를 처음 시작한 1982년부터 지난해(2017년)까지 팀 타격 데이터를 가지고 dplyr를 어떻게 활용하는지 알아보도록 하겠습니다.
인터넷 포털 사이트 등에서 dplyr를 찾아 이 포스트를 찾아오신 분이라면 이미 R가 무엇인지 잘 알고 계실 겁니다.
혹시 모르시는 분들께 R 홈페이지에 올라온 대로 설명드리면 R는 통계 계산과 그래픽에 활용하는 무료 소프트웨어 환경(R is a free software environment for statistical computing and graphics)"입니다.
무료니까 누구든 이 페이지에서 원하시는 R 버전을 선택해 설치하실 수 있습니다.
2018년 8월 현재 최신 버전은 3.5.1이며 MS 윈도에 이를 설치하시려면 이 링크를 누르시면 됩니다.
이 포스트 제목에는 분명 '최대한 친절하게'라고 썼지만 프로그램 설치법까지 모르실 거라고는 생각하지 않으니 따로 말씀드리지 않겠습니다.
설치를 마치고 R를 실행하시면 아래 화면이 나타납니다. 이 창을 흔히 'R 콘솔(Console)'이라고 부릅니다. 창 제목에도 그렇게 나와 있습니다.
여기서 '>' 표시 뒤에 명령어를 입력하면 프로그래밍(코딩)을 진행할 수 있습니다. 코딩은 '이러저러한 게 하고 싶다'고 컴퓨터에게 알려주는 일을 뜻합니다
제가 "print('Hello, World!')"라고 쓴 건 Hello, World!를 (화면에) 출력하고 싶다고 컴퓨터에게 알려준 겁니다. 이 "Hello, World!" 프로그램은 코딩을 처음 배울 때 제일 많이 쓰는 기본 예제입니다.
이 22글자도 치기 귀찮으시다면 '1+1'을 입력해 보세요. 그러면 '2'를 표시할 겁니다.
기껏 R를 깔았는데 어떻게 사용해야 할지 모르실 때는 계산기로 쓰셔도 된다는 뜻입니다. (네, 재미없는 농담 죄송합니다.)
이제 두 번째 명령어(함수)를 배울 차례가 됐습니다.
두 번째 함수는 R에 패키지를 설치하라는 뜻인 'install.packages()'입니다.
패키지는 R에 기본으로 들어 있지 않은 각종 기능을 추가할 수 있는 묶음이라고 생각하시면 쉽습니다.
그렇다면 이번에 우리가 설치해야 하는 패키지 이름은 뭘까요? 맞습니다. 'dplyr'입니다. dplyr를 설치하려면 아래처럼 입력하면 그만입니다.
install.packages('dplyr')
R에서는 패키지를 설치했다고 곧바로 사용할 수 있게 되는 건 아닙니다. 패키지를 불러오는 절차를 한 번 더 거쳐야 합니다. 이때는 'library()'라는 함수를 씁니다.
library('dplyr')
아무 반응도 없다고요? 네, 그러면 dplyr를 불러오는 데 성공하신 겁니다. 축하드립니다. 이제 누군가 dplyr 이야기를 꺼내면 '나도 안다'고 말씀하실 수 있게 됐습니다.
새로운 패키지를 불러들이고 나면 사용할 수 있는 함수가 늘어납니다. dplyr에서 제일 중요한 함수는 아래 있는 여섯 가지입니다. 이번 포스트도 이 여섯 가지 함수에 초점을 맞춥니다.
함수 | 기능 | 사용법 |
arrange() | 행 정렬 | arrange(데이터, 변수 이름) |
filter() | 행 추출 | filter(데이터, 조건) |
group_by() | 행 결합 | group_by(조건) |
mutate() | 열 추가 | mutate(데이터, 새 변수 = 계산식) |
select() | 열 선택 | select(데이터, 변수 이름 또는 인덱스) |
summarise() | 행 요약 | summarise(데이터, 새 변수 = 계산식) |
이 여섯 가지 함수를 활용하려면 일단 처리해야 할 데이터가 있어야겠죠?
앞서 말씀드린 것처럼 1982~2017 프로야구 팀 타격 기록을 활용하도록 하겠습니다. 아래 링크에서 내려받으시면 됩니다.
이 데이터는 쉼표로 구분된 값(CSV·Comma Separated Value)이라는 형태입니다. CSV는 텍스트 파일에서 각 열을 쉼표로 구분한 형태라고 생각하시면 됩니다.
이 파일을 확인하는 가장 쉬운 방법은 MS 엑셀을 활용하는 것. 컴퓨터에 이미 MS 엑셀이 깔려 있다면 그냥 더블클릭만으로 내용을 확인할 수 있습니다.
아니면 아래처럼 구글 스프레드시트를 활용하셔도 됩니다. 이번 데이터는 행이 284개, 열이 21개인 구조입니다.
R 역시 CSV 파일을 읽을 수 있도록 함수를 제공하고 있습니다.
이름 그대로 'read.csv()'가 그 주인공. 이 파일을 읽으시려면 read.csv('kbo.csv')라고만 치셔도 무방합니다.
단, 이때 이 파일이 R 작업 디렉토리(폴더)에 들어 있어야 합니다.
MS 윈도에서 기본 작업 디렉토리는 기본적으로 '문서'입니다. 그러니까 한번도 작업 폴더를 바꾸신 적이 없다면 내 문서에 이 파일을 내려받으시면 됩니다.
만약 작업 디렉토리를 바꾸고 싶으실 때는 메뉴에서 File - Change dir...를 선택하시면 됩니다. 이게 제일 간단하고 쉬운 방법입니다.
콘솔에 직접 입력하고 싶으실 때는 'setwd()'라는 함수 뒤에 원하는 폴더를 쓰셔도 같은 효과를 경험하실 수 있습니다.
이렇게 원하는 위치에 파일 저장을 마치셨으면 진짜 파일을 불러옵니다.
read.csv('kbo.csv')
파일 내용이 잘 보였으리라 믿습니다.
그런데 이렇게 그냥 내용을 읽기만 하는 걸로는 다음 번 작업에 활용하기가 곤란합니다.
그래서 컴퓨터 메모리 안에 빈 방을 만들어 이 내용을 담아두는 방법을 씁니다. 프로그래밍에서는 이런 빈 방을 '변수'라고 부릅니다.
R에서 변수에 어떤 값을 넣을 때는 '<-' 또는 '=' 기호를 씁니다. 이번에는 kbo라는 빈 방에 이 결과를 넣어보도록 하겠습니다. 이렇게 치시면 됩니다.
kbo <- read.csv('kbo.csv')
이번에는 아무 내용도 출력하지 않습니다. 변수 내용을 확인하시려면 그냥 변수 이름만 치시면 됩니다. > 다음에 kbo라고 쓰시면 print(kbo)라고 치셨을 때와 같은 화면이 나타날 겁니다.
문제가 있다면 자료가 너무 많아서 어떤 모양인지 알아보기가 쉽지 않다는 것.
이럴 때는 head()를 써보시면 좋습니다. head()는 어떤 데이터에서 처음 여섯 줄만 보여주는 구실을 합니다.
head(kbo)
## 연도 팀 경기 타석 타수 득점 안타 X2루타 X3루타 홈런 총루타 타점 도루 ## 1 1982 MBC 80 3061 2686 419 757 124 12 65 1100 381 134 ## 2 1982 삼성 80 3043 2647 429 705 126 18 57 1038 374 147 ## 3 1982 OB 80 3098 2745 399 778 137 23 57 1132 362 106 ## 4 1982 해태 80 2990 2665 374 696 110 14 84 1086 332 155 ## 5 1982 롯데 80 3062 2628 353 674 112 8 59 979 325 83 ## 6 1982 삼미 80 2954 2653 302 637 117 20 40 914 272 74 ## 도루실패 볼넷 몸에.맞는.공 고의사구 삼진 병살 희생번트 희생플라이 ## 1 60 268 47 20 316 56 32 27 ## 2 42 307 30 2 349 50 36 18 ## 3 61 247 41 22 254 35 46 18 ## 4 52 235 41 12 296 59 28 21 ## 5 53 326 40 8 315 61 41 27 ## 6 43 221 29 3 369 44 33 17
텍스트 형태로 화면에 표시하다 보니 폭이 잘 맞지 않지만 일단 원하는 자료는 다 들어왔습니다.
여기서 눈에 띄는 또 한 가지는 '2루타', '3루타'로 되어 있던 열 이름 앞에 'X'가 붙었다는 점입니다.
R에서는 열 이름을 숫자로 시작할 수 없기 때문에 자동으로 이렇게 바뀐 겁니다.
'몸에 맞는 공'이 '몸에.맞는.공'으로 바뀐 건 공백 때문입니다.
혹시 이런 생각하시는 분은 안 계신가요? '왜 여섯 줄이냐? 나는 다섯 줄만 보고 싶다.'
걱정 없습니다. head(변수, 숫자) 형태로 쓰시면 처음부터 원하는 행까지 데이터 확인이 가능합니다.
거꾸로 'tail()'이라는 함수도 있습니다. head()와 반대로 끝에서부터 자료를 보여주는 구실을 합니다. tail()도 tail(변수, 숫자) 형태로 쓸 수 있습니다.
이제 dplyr 공부를 시작할 준비를 모두 마쳤습니다.
원래 시험 때도 공부할 준비를 마쳤으면 잠시 쉬어주는 게 예의. 기지개라도 한번 켜시면서 다음으로 넘어가 볼까요?
데이터를 처리할 때 꼭 필요한 기능을 꼽으라면 역시 정렬입니다.
dplyr로 데이터를 정렬할 때 쓰는 함수는? 네, 위에서 보신 것처럼 arrange()입니다.
지금 우리가 쓰고 있는 데이터는 기본적으로 '연도'를 오름차순으로 정렬한 형태입니다. 이걸 팀 이름 순서로 바꾸려면 어떻게 하면 될까요?
arrange()는 arrange(데이터, 변수) 순서로 활용합니다. 이때 데이터는 'kbo'이고, 변수는 '팀'이 됩니다.
그렇다면 arrange(kbo, 팀)이라고 입력하면 우리가 원하는 결과를 얻을 수 있을 겁니다.
결과가 다 나오면 너무 기니까 head() 함수를 써서 확인해 보겠습니다. 이렇게 함수를 겹쳐 쓸 때는 어떤 함수 안에 다른 함수를 포함하면 그만입니다.
head(arrange(kbo, 팀))
## 연도 팀 경기 타석 타수 득점 안타 X2루타 X3루타 홈런 총루타 타점 도루 ## 1 2002 KIA 133 5200 4575 643 1230 220 14 120 1838 611 155 ## 2 2003 KIA 133 5127 4448 657 1211 219 16 129 1849 626 146 ## 3 2004 KIA 133 5190 4426 643 1182 224 9 143 1853 610 127 ## 4 2005 KIA 133 4848 4234 541 1102 183 13 99 1608 507 101 ## 5 2006 KIA 126 4754 4181 476 1067 191 22 62 1488 431 93 ## 6 2007 KIA 126 4811 4204 499 1080 198 16 73 1529 466 70 ## 도루실패 볼넷 몸에.맞는.공 고의사구 삼진 병살 희생번트 희생플라이 ## 1 39 454 91 32 914 107 45 35 ## 2 67 505 42 18 721 72 94 37 ## 3 54 549 79 22 693 118 82 54 ## 4 43 430 74 24 718 101 79 31 ## 5 43 390 55 20 650 90 102 26 ## 6 44 428 55 7 630 117 78 45
일단 잘 나왔습니다. KIA가 제일 먼저 나온 건 알파벳부터 오름차순으로 정렬했기 때문입니다.
내림차순으로 정렬하고 싶을 때는 어떻게 하면 될까요? 이때는 변수 이름 앞에 desc만 쓰면 됩니다. desc는 내림차순을 뜻하는 'descending'을 줄인 말입니다.
그렇다면 arrange(kbo, desc(팀))이라고 쓰면 될 테고 그 결과는 아래와 같습니다
arrange(kbo, desc(팀))
## 연도 팀 경기 타석 타수 득점 안타 X2루타 X3루타 홈런 총루타 타점 ## 1 2008 히어로즈 126 4834 4317 499 1149 190 19 70 1587 471 ## 2 2009 히어로즈 133 5211 4486 683 1219 228 20 153 1946 650 ## 3 1996 현대 126 4729 4127 493 1001 171 21 106 1532 462 ## 4 1997 현대 126 4680 4032 497 994 179 19 82 1457 459 ## 5 1998 현대 126 4779 4161 633 1123 216 21 142 1807 587 ## 6 1999 현대 132 5260 4456 699 1210 187 18 143 1862 652 ## 도루 도루실패 볼넷 몸에.맞는.공 고의사구 삼진 병살 희생번트 희생플라이 ## 1 97 57 396 37 20 713 114 51 33 ## 2 192 67 547 63 22 905 116 64 48 ## 3 112 90 396 72 35 747 66 104 30 ## 4 112 78 424 72 33 720 92 122 28 ## 5 134 85 413 74 16 820 69 91 38 ## 6 109 65 537 98 22 780 88 127 42
물론 head()만 이렇게 쓸 수 있는 건 아닙니다. tail(arrange(kbo, desc(팀)), 5) 같은 표현도 가능합니다.
이러면 팀 이름을 내림차순으로 정렬한 데이터 가운데 끝에서 다섯 번째까지 데이터를 출력하게 됩니다.
tail(arrange(kbo, desc(팀)), 5)
## 연도 팀 경기 타석 타수 득점 안타 X2루타 X3루타 홈런 총루타 타점 도루 ## 279 2013 KIA 128 5051 4318 587 1125 195 13 88 1610 545 141 ## 280 2014 KIA 128 5023 4443 662 1279 246 27 121 1942 631 121 ## 281 2015 KIA 144 5454 4777 648 1197 223 22 136 1872 602 115 ## 282 2016 KIA 144 5696 4999 803 1429 264 28 170 2259 754 101 ## 283 2017 KIA 144 5841 5142 906 1554 292 29 170 2414 868 76 ## 도루실패 볼넷 몸에.맞는.공 고의사구 삼진 병살 희생번트 희생플라이 ## 279 47 537 75 8 864 110 78 42 ## 280 63 416 62 11 870 95 67 35 ## 281 50 454 101 16 1126 105 79 43 ## 282 50 499 87 12 997 109 66 45 ## 283 34 499 89 19 891 118 55 56
지금 보기는 식이 간단하지만 명령어가 길어지면 이렇게 함수(함수(함수(함수())))로 점점 모양이 복잡해집니다.
그래서 dplyr는 '파이프(pipe)'라는 기능을 가지고 있습니다.
현실 세계에서 파이프가 한 곳에서 다른 곳으로 물 같은 액체를 보낼 수 있게 도와주는 것처럼 이 녀석도 함수에서 다른 함수로 자료를 손쉽게 보내주는 구실을 합니다.
R에서 파이프는 '%>%'로 표시합니다.
파이프를 쓰면 바로 위에서 쓴 명령어를 arrange(kbo, desc(팀)) %>% tail(5)로 바꿀 수 있습니다.
arrange(kbo, desc(팀)) %>% tail(5)
## 연도 팀 경기 타석 타수 득점 안타 X2루타 X3루타 홈런 총루타 타점 도루 ## 279 2013 KIA 128 5051 4318 587 1125 195 13 88 1610 545 141 ## 280 2014 KIA 128 5023 4443 662 1279 246 27 121 1942 631 121 ## 281 2015 KIA 144 5454 4777 648 1197 223 22 136 1872 602 115 ## 282 2016 KIA 144 5696 4999 803 1429 264 28 170 2259 754 101 ## 283 2017 KIA 144 5841 5142 906 1554 292 29 170 2414 868 76 ## 도루실패 볼넷 몸에.맞는.공 고의사구 삼진 병살 희생번트 희생플라이 ## 279 47 537 75 8 864 110 78 42 ## 280 63 416 62 11 870 95 67 35 ## 281 50 454 101 16 1126 105 79 43 ## 282 50 499 87 12 997 109 66 45 ## 283 34 499 89 19 891 118 55 56
괄호 사용이 줄어드는 것 말고 장점이 하나 더 있습니다. tail(arrange())로 쓴 것보다 이 쪽이 어떤 작업을 하는지 한눈에 더 잘 들어오지 않나요?
dplyr에는 데이터를 추출하는 함수가 두 개 들어있습니다. 행을 추출할 때는 filter(), 열을 추출할 때는 select()입니다.
그렇다면 2017년 데이터만 뽑아내고 싶을 때는 어떻게 하면 될까요?
filter()는 filter(데이터, 조건) 형태로 씁니다. 데이터는 계속 kbo입니다. 어느 해 데이터인지는 '연도'라는 열에 들어 있습니다.
그러면 filter(kbo, 연도=2017)이 될 겁니다.
그런데 이렇게 치면 'Error: `연도` (`연도 = 2017`) must not be named, do you need `==`?'라고 에러 메시지가 뜹니다.
저 설명이 알려주고 있는 것처럼 조건에서 똑같다고 표시할 때는 '='가 아니라 '=='라고 써야 합니다. '='는 어떤 변수에 데이터를 넣으라는 뜻이니까요.
그래서 정답은 filter(kbo, 연도==2017)이 됩니다. 파이프를 써서 앞부분만 확인하려면?
네, 그렇습니다. filter(kbo, 연도==2017) %>% head()가 정답입니다.
filter(kbo, 연도==2017) %>% head()
## 연도 팀 경기 타석 타수 득점 안타 X2루타 X3루타 홈런 총루타 타점 도루 ## 1 2017 두산 144 5833 5102 849 1499 270 20 178 2343 812 69 ## 2 2017 KIA 144 5841 5142 906 1554 292 29 170 2414 868 76 ## 3 2017 NC 144 5790 5079 786 1489 277 19 149 2251 739 93 ## 4 2017 넥센 144 5712 5098 789 1479 267 30 141 2229 748 70 ## 5 2017 SK 144 5564 4925 761 1337 222 15 234 2291 733 53 ## 6 2017 롯데 144 5671 4994 743 1425 250 17 151 2162 697 92 ## 도루실패 볼넷 몸에.맞는.공 고의사구 삼진 병살 희생번트 희생플라이 ## 1 33 541 95 19 960 120 48 47 ## 2 34 499 89 19 891 118 55 56 ## 3 32 471 130 19 979 119 62 48 ## 4 34 468 83 15 1066 129 21 42 ## 5 42 427 113 20 1100 97 57 41 ## 6 44 457 112 33 1018 146 76 32
그러면 2017년 자료 중에서 안타, 2루타, 3루타, 홈런만 확인하고 싶을 때는 어떻게 할까요?
이번에는 열을 선택해야 하니까 select()를 씁니다.
위에서 살펴본 것처럼 R 변수 이름 규칙 때문에 바뀐 게 있으니까 select(kbo, 안타, X2루타, X3루타, 홈런)으로 쓰면 됩니다.
select(kbo, 안타, X2루타, X3루타, 홈런)
이렇게 써도 잘 작동하지만 이건 R에서 데이터를 다루는 원칙에는 맞지 않습니다.
R는 데이터를 한꺼번에 묶을 때 'concatenate'를 줄인 c()를 쓰도록 하고 있습니다.
그냥 c(안타, X2루타, X3루타, 홈런)으로 쓰면 그만입니다. 그러면 select(kbo, c(안타, X2루타, X3루타, 홈런))이 됩니다.
아직은 연도를 적용하기 전이라서 이렇게 치면 1982년부터 2017년까지 자료가 모두 뜹니다. 2017년만 뽑아 내려면 filter()를 써야겠죠?
이때는 데이터가 kbo가 아니라 위에서 본 것처럼 filter(kbo, 연도==2017)이 됩니다.
만약 파이프가 없는 상태로 head()까지 써서 이를 나타내려면 'head(select(filter(kbo, 연도==2017), c(안타, X2루타, X3루타, 홈런)))' 이렇게 써야 합니다.
괄호를 어디에 어떻게 써야 할지도 헷갈릴 지경입니다. 우리는 파이프를 알고 있으니까 이렇게 쓸 필요가 없습니다.
filter(kbo, 연도==2017) %>% select(안타, X2루타, X3루타, 홈런) %>% head()
## 안타 X2루타 X3루타 홈런 ## 1 1499 270 20 178 ## 2 1554 292 29 170 ## 3 1489 277 19 149 ## 4 1479 267 30 141 ## 5 1337 222 15 234 ## 6 1425 250 17 151
어떤가요? 이 정도만 전체 명령어가 길어져도 파이프를 쓰는 편이 훨씬 편하고 직관적이지 않습니까?
아, 경우에 따라서는 특정 열만 빼고 선택하고 싶으실 때가 있을 겁니다. 이때는 변수 이름 앞에 '-'를 붙여주시면 됩니다.
그러니까 2017년 데이터 가운데 안타, 2루타, 3루타, 홈런을 빼고 싶으시면 이렇게 쓰면 되는 겁니다.
filter(kbo, 연도==2017) %>% select(-안타, -X2루타, -X3루타, -홈런) %>% head()
## 연도 팀 경기 타석 타수 득점 총루타 타점 도루 도루실패 볼넷 ## 1 2017 두산 144 5833 5102 849 2343 812 69 33 541 ## 2 2017 KIA 144 5841 5142 906 2414 868 76 34 499 ## 3 2017 NC 144 5790 5079 786 2251 739 93 32 471 ## 4 2017 넥센 144 5712 5098 789 2229 748 70 34 468 ## 5 2017 SK 144 5564 4925 761 2291 733 53 42 427 ## 6 2017 롯데 144 5671 4994 743 2162 697 92 44 457 ## 몸에.맞는.공 고의사구 삼진 병살 희생번트 희생플라이 ## 1 95 19 960 120 48 47 ## 2 89 19 891 118 55 56 ## 3 130 19 979 119 62 48 ## 4 83 15 1066 129 21 42 ## 5 113 20 1100 97 57 41 ## 6 112 33 1018 146 76 32
야구에서 타자 기록 중 가장 기본이 되는 건 타율이고 '안타÷타수'로 계산합니다.
kbo 데이터에는 아직 이 기록이 없습니다. 새로 열을 만들어 넣어야 하는 겁니다.
이럴 때 쓰는 함수는? 네, 그렇습니다. mutate()입니다.
이 함수는 'mutate(데이터, 새 변수 = 계산식)' 형태로 씁니다.
우리는 kbo라는 데이터에 '타율'이라는 새 열을 만드는데, 그 안에 '안타/타수'를 넣으려고 합니다. (÷와 /가 같은 뜻인 거 설마 모르시지 않겠죠?)
이를 종합하면 이렇게 쓰면 됩니다.
kbo %>% mutate(타율=안타/타수) %>% head()
## 연도 팀 경기 타석 타수 득점 안타 X2루타 X3루타 홈런 총루타 타점 도루 ## 1 1982 MBC 80 3061 2686 419 757 124 12 65 1100 381 134 ## 2 1982 삼성 80 3043 2647 429 705 126 18 57 1038 374 147 ## 3 1982 OB 80 3098 2745 399 778 137 23 57 1132 362 106 ## 4 1982 해태 80 2990 2665 374 696 110 14 84 1086 332 155 ## 5 1982 롯데 80 3062 2628 353 674 112 8 59 979 325 83 ## 6 1982 삼미 80 2954 2653 302 637 117 20 40 914 272 74 ## 도루실패 볼넷 몸에.맞는.공 고의사구 삼진 병살 희생번트 희생플라이 ## 1 60 268 47 20 316 56 32 27 ## 2 42 307 30 2 349 50 36 18 ## 3 61 247 41 22 254 35 46 18 ## 4 52 235 41 12 296 59 28 21 ## 5 53 326 40 8 315 61 41 27 ## 6 43 221 29 3 369 44 33 17 ## 타율 ## 1 0.2818317 ## 2 0.2663393 ## 3 0.2834244 ## 4 0.2611632 ## 5 0.2564688 ## 6 0.2401055
파이프를 쓰는 방식이 조금 달라진 것 눈치채셨습니까? 지금까지는 첫 함수에는 데이터 이름을 따로 넣었습니다. 그러니까 이렇게 썼던 것.
mutate(kbo, 타율=안타/타수) %>% head()
사실은 데이터부터 곧바로 파이프를 써도 관계가 없습니다. 이 쪽이 더 직관적입니다. 그렇죠?
이렇게 타율을 구하고 나니 연도별 리그 평균 타율을 계산하고 싶다는 생각이 듭니다. 이럴 때는 어떻게 하면 될까요?
네, 이럴 때 쓰라고 group_by() 함수가 기다리고 있습니다.
우리는 연도를 기준으로 묶고 싶은 거니까 group_by(연도)라고 쓰면 그만입니다. 이렇게 말입니다.
kbo %>% group_by(연도)
## # A tibble: 283 x 21 ## # Groups: 연도 [36] ## 연도 팀 경기 타석 타수 득점 안타 X2루타 X3루타 홈런 총루타 ## <int> <fct> <int> <int> <int> <int> <int> <int> <int> <int> <int> ## 1 1982 MBC 80 3061 2686 419 757 124 12 65 1100 ## 2 1982 삼성 80 3043 2647 429 705 126 18 57 1038 ## 3 1982 OB 80 3098 2745 399 778 137 23 57 1132 ## 4 1982 해태 80 2990 2665 374 696 110 14 84 1086 ## 5 1982 롯데 80 3062 2628 353 674 112 8 59 979 ## 6 1982 삼미 80 2954 2653 302 637 117 20 40 914 ## 7 1983 삼성 100 3847 3383 448 889 143 14 90 1330 ## 8 1983 해태 100 3734 3340 423 892 130 15 78 1286 ## 9 1983 MBC 100 3715 3273 405 837 145 21 45 1159 ## 10 1983 OB 100 3766 3330 418 863 142 26 50 1207 ## # ... with 273 more rows, and 10 more variables: 타점 <int>, 도루 <int>, ## # 도루실패 <int>, 볼넷 <int>, 몸에.맞는.공 <int>, 고의사구 <int>, ## # 삼진 <int>, 병살 <int>, 희생번트 <int>, 희생플라이 <int>
이상한 모양이 등장했습니다. 이렇게 생긴 데이터 형태를 (설명에 나온 것처럼) tibble 또는 tbl_df라고 부릅니다. 이때 df는 데이터 프레임(Data Frame)이라는 뜻입니다.
요컨대 tibble은 데이터 프레임을 현대적으로 업그레이드한 형태라고 생각하시면 됩니다.
데이터 프레임은 그럼 뭘까요? MS 엑셀이 데이터를 다루는 방식이 바로 데이터 프레임입니다. 지금까지 우리가 사용한 CSV도 마찬가지.
요컨대 행과 열이 있는 표 형태로 데이터를 저장하는 방식을 데이터 프레임이라고 생각하시면 쉽습니다.
다시 본론으로 돌아와서 우리는 연도별 리그 평균 타율을 구하려고 합니다.
리그 기록은 기본적으로 각 구단 기록을 모두 더한 결과물입니다. R에서 이렇게 모두 더하라는 함수는 sum()입니다.
타율은 여전히 '안타÷타수'로 계산할 수 있으니까 '(리그) 타율 = sum(안타)/sum(타수)'가 됩니다.
이 계산식을 어디에 넣어야 할까요? 그렇습니다. summarise()입니다.
리그 평균을 구하는 것도 전체 데이터를 요약하는 작업입니다.
이렇게 생각하면 summarise() 함수를 쓰는 게 당연한 일입니다.
이미 연도별 그루핑은 해놓은 상태니까 이렇게 쓰면 됩니다.
kbo %>% group_by(연도) %>% summarise(타율=sum(안타)/sum(타수))
## # A tibble: 36 x 2 ## 연도 타율 ## <int> <dbl> ## 1 1982 0.265 ## 2 1983 0.256 ## 3 1984 0.254 ## 4 1985 0.260 ## 5 1986 0.251 ## 6 1987 0.265 ## 7 1988 0.268 ## 8 1989 0.257 ## 9 1990 0.257 ## 10 1991 0.256 ## # ... with 26 more rows
예상대로 잘 나왔습니다. 꼭 mutate()를 쓰시고 싶거나 총 안타와 총 타수를 표시하고 싶으실 때는 이렇게 쓰셔도 됩니다.
kbo %>% group_by(연도) %>% summarise(총안타=sum(안타), 총타수=sum(타수)) %>% mutate(타율=총안타/총타수)
## # A tibble: 36 x 4 ## 연도 총안타 총타수 타율 ## <int> <int> <int> <dbl> ## 1 1982 4247 16024 0.265 ## 2 1983 5102 19951 0.256 ## 3 1984 4995 19703 0.254 ## 4 1985 5700 21890 0.260 ## 5 1986 6234 24879 0.251 ## 6 1987 6666 25125 0.265 ## 7 1988 6747 25163 0.268 ## 8 1989 7099 27654 0.257 ## 9 1990 7077 27566 0.257 ## 10 1991 8514 33233 0.256 ## # ... with 26 more rows
우리는 타율만 필요한 상태니까 처음에 썼던 버전을 계속 쓰겠습니다.
이번에는 계산 결과 중에서 필요한 데이터만 뽑아내는 걸 연습해 보겠습니다.
연도별 타율 가운데 2001년 리그 평균 타율을 구하고 싶을 때는 어떻게 해야 할까요?
별 거 없습니다. 파이프를 이어가기면 하면 됩니다.
kbo %>% group_by(연도) %>% summarise(타율=sum(안타)/sum(타수)) %>% filter(연도==2001)
## # A tibble: 1 x 2 ## 연도 타율 ## <int> <dbl> ## 1 2001 0.274
난도를 조금 높여보겠습니다. 리그 평균 타율이 제일 높았던 연도를 알아보려면 어떻게 해야 할까요?
힌트는 R에서 최댓값을 구하는 함수는 max()라는 점입니다. 어떻게요?
kbo %>% group_by(연도) %>% summarise(타율=sum(안타)/sum(타수)) %>% filter(타율==max(타율))
## # A tibble: 1 x 2 ## 연도 타율 ## <int> <dbl> ## 1 2016 0.290
여기서 아쉬운 점이 있습니다. 명령어 전체가 너무 길다 보니까 화면에서 잘립니다.
화면에서 보이지 않는 거야 저처럼 설명을 드리는 처지가 아니라면 별 관계가 없는 게 사실. 그래도 잘 보이지 않으면 직관적으로 명령을 이해하기가 쉽지 않습니다.
그럴 때는 그냥 행을 나누면 됩니다. 이렇게 말입니다.
kbo %>%
group_by(연도) %>%
summarise(타율=sum(안타)/sum(타수)) %>%
filter(타율==max(타율))
위에 있는 코드를 그냥 그대로 콘솔에 붙여 넣으셔도 한 줄로 된 코드와 100% 똑같이 작동합니다. 그냥 행갈이만 한 거니까요.
지금까지는 곧바로 결과를 확인하려고 명령어를 전부 한 줄에 넣었습니다.
꼭 그럴 필요는 없습니다. 데이터를 처리한 걸 별도로 빈 방에 담아 새 데이터를 만들 수도 있습니다.
예를 들어 연도별 타율(batting average)을 avg라는 함수에 넣고 싶다면 이렇게 쓰면 됩니다.
avg <- kbo %>% group_by(연도) %>% summarise(타율=sum(안타)/sum(타수))
avg
## # A tibble: 36 x 2 ## 연도 타율 ## <int> <dbl> ## 1 1982 0.265 ## 2 1983 0.256 ## 3 1984 0.254 ## 4 1985 0.260 ## 5 1986 0.251 ## 6 1987 0.265 ## 7 1988 0.268 ## 8 1989 0.257 ## 9 1990 0.257 ## 10 1991 0.256 ## # ... with 26 more rows
혹시 잊으셨을까 봐 말씀드리면 데이터(변수) 이름만 콘솔에 치는 건 그 변수 내용을 보여달라는 뜻입니다.
물론 행갈이를 해서 저 내용을 이런 식으로 써도 같은 결과를 얻을 수 있습니다.
avg <- kbo %>%
group_by(연도) %>%
summarise(타율=sum(안타)/sum(타수))
또 변수 입력 기호 방향을 반대로 그러니까 파이프 방향으로 써도 자료가 들어갑니다.
kbo %>%
group_by(연도) %>%
summarise(타율=sum(안타)/sum(타수)) -> avg
avg
## # A tibble: 36 x 2 ## 연도 타율 ## <int> <dbl> ## 1 1982 0.265 ## 2 1983 0.256 ## 3 1984 0.254 ## 4 1985 0.260 ## 5 1986 0.251 ## 6 1987 0.265 ## 7 1988 0.268 ## 8 1989 0.257 ## 9 1990 0.257 ## 10 1991 0.256 ## # ... with 26 more rows
이렇게 연도별 자료를 계산하고 나니 선 그래프로 추이를 확인하고 싶어지시죠? ggplot2라는 패키지를 써서 그려보도록 하겠습니다.
ggplot2 역시 dplyr처럼 tidyverse 패키지 가운데 일부로 시각화를 도와주는 구실을 합니다.
ggplot2를 어떻게 쓰는지 알아보고 싶으신 분은 '최대한 친절하게 쓴 R로 그래프 그리기(feat. ggplot2)' 포스트가 도움이 될 수 있습니다.
R에서 패키지를 쓰려면 제일 먼저 해야 할 일은?
네, install.packages() 함수로 패키지를 설치하는 겁니다. 그리고 library() 함수로 패키지를 로드해야 합니다.
install.packages('ggplot2')
library('ggplot2')
이어서 x축은 연도, y축은 타율을 나타내는 선 그래프를 그리라고 명령해 보겠습니다.
ggplot(data=avg, aes(x=연도, y=타율)) + geom_line()
예쁘게 잘 나왔습니다. 물론 파이프만 계속 써서 똑같은 그림을 그릴 수도 있습니다. 이렇게 말입니다.
kbo %>%
group_by(연도) %>%&
summarise(타율=sum(안타)/sum(타수)) %>%
ggplot(., aes(x=연도, y=타율)) + geom_line()
원래 data=avg가 차지하고 있던 자리를 '.'이 차지해야 한다는 것만 생각하면 어려울 게 없는 코드입니다.
이제 dplyr를 어떻게 쓰는지 어느 정도 감을 잡을셨을 줄로 믿습니다. 지금부터는 연습 문제 형태로 조금 더 디테일한 세계로 들어가 보겠습니다.
문1. 타격 기록 중 가장 기본이 되는 타율/출루율/장타력과 OPS(출루율+장타력) 변수(열)를 만드시오.
답1. 바로 mutate() 함수를 떠올리셨죠? 그렇다면 이제 필요한 건 공식뿐입니다.
타율은 이미 '안타 ÷ 타수'라는 걸 알고 있습니다. 출루율과 장타력은 아래 공식으로 계산합니다.
kbo 데이터에는 이미 '단타 + 2×2루타 + 3×3루타 + 4×홈런'을 계산한 변수가 들어 있습니다.
바로 총루타입니다. 따라서 장타력은 '총루타 ÷ 타수'로 바꿀 수 있습니다.
OPS는 문자 그대로 '출루율 + 장타력'이 전부입니다. 그래서 이렇게 쓰면 됩니다. (※결과에는 head 적용)
kbo <- mutate(kbo, 타율=안타/타수,
출루율 = (안타+볼넷+몸에.맞는.공)/(타수+볼넷+몸에.맞는.공+희생플라이),
장타력=총루타/타수,
ops=출루율+장타력)
## 연도 팀 경기 타석 타수 득점 안타 X2루타 X3루타 홈런 총루타 타점 도루 ## 1 1982 MBC 80 3061 2686 419 757 124 12 65 1100 381 134 ## 2 1982 삼성 80 3043 2647 429 705 126 18 57 1038 374 147 ## 3 1982 OB 80 3098 2745 399 778 137 23 57 1132 362 106 ## 4 1982 해태 80 2990 2665 374 696 110 14 84 1086 332 155 ## 5 1982 롯데 80 3062 2628 353 674 112 8 59 979 325 83 ## 6 1982 삼미 80 2954 2653 302 637 117 20 40 914 272 74 ## 도루실패 볼넷 몸에.맞는.공 고의사구 삼진 병살 희생번트 희생플라이 ## 1 60 268 47 20 316 56 32 27 ## 2 42 307 30 2 349 50 36 18 ## 3 61 247 41 22 254 35 46 18 ## 4 52 235 41 12 296 59 28 21 ## 5 53 326 40 8 315 61 41 27 ## 6 43 221 29 3 369 44 33 17 ## 타율 출루율 장타력 ops ## 1 0.2818317 0.3540291 0.4095309 0.7635600 ## 2 0.2663393 0.3471019 0.3921420 0.7392440 ## 3 0.2834244 0.3493936 0.4123862 0.7617798 ## 4 0.2611632 0.3281567 0.4075047 0.7356613 ## 5 0.2564688 0.3442569 0.3725266 0.7167835 ## 6 0.2401055 0.3037671 0.3445156 0.6482828
문2. OPS가 0.7 이상이면서 팀 홈런이 70개 미만이 몇 개인지 구하시오.
답2. '~면서'라는 건 '그리고(and)'라는 뜻입니다. 이렇게 논리적인 접근이 필요할 때는 '논리 연산자'를 씁니다.
R에서 '그리고'는 '&'로 표시합니다. '또는'(or)은 '|'입니다.
같은 건 '=='라는 갈 아실 테고 다른 건 '!='입니다.
또 크다(>), 크거나 같다(>=), 작다(<), 작거나 같다(<=) 같은 연산자도 씁니다.
따라서 ops가 0.7 이상인 건 'ops >= 0.7', '~면서'는 '&', 홈런 70개 미만은 '홈런 < 70'라고 쓸 수 있습니다.
이걸 어디에 넣어야 할까요? 네, filter()입니다. filter(ops >= 0.7 & 홈런 < 70)처럼 쓰면 됩니다.
이를 파이프로 연결하면 이렇게 쓸 수 있습니다.
kbo %>% filter(ops >= 0.7 & 홈런 < 70)
## 연도 팀 경기 타석 타수 득점 안타 X2루타 X3루타 홈런 총루타 타점 ## 1 1982 MBC 80 3061 2686 419 757 124 12 65 1100 381 ## 2 1982 삼성 80 3043 2647 429 705 126 18 57 1038 374 ## 3 1982 OB 80 3098 2745 399 778 137 23 57 1132 362 ## 4 1982 롯데 80 3062 2628 353 674 112 8 59 979 325 ## 5 1985 OB 110 4189 3667 473 954 146 27 67 1355 432 ## 6 1987 롯데 108 4155 3625 432 970 161 27 40 1305 400 ## 7 1987 빙그레 108 4054 3547 410 972 144 22 48 1304 370 ## 8 1988 롯데 108 4095 3578 482 967 142 18 68 1349 446 ## 9 1990 LG 120 4661 4024 578 1089 156 40 61 1508 528 ## 10 1992 롯데 126 4904 4205 663 1213 211 62 68 1752 619 ## 11 1996 쌍방울 126 4805 4111 545 1085 192 33 58 1517 489 ## 12 2005 두산 133 4922 4256 596 1147 183 17 63 1553 558 ## 13 2008 두산 126 4975 4344 647 1198 166 37 68 1642 598 ## 14 2013 LG 128 4934 4291 616 1210 194 38 59 1657 574 ## 15 2013 롯데 128 4978 4289 556 1118 208 18 61 1545 522 ## 도루 도루실패 볼넷 몸에.맞는.공 고의사구 삼진 병살 희생번트 희생플라이 ## 1 134 60 268 47 20 316 56 32 27 ## 2 147 42 307 30 2 349 50 36 18 ## 3 106 61 247 41 22 254 35 46 18 ## 4 83 53 326 40 8 315 61 41 27 ## 5 107 76 354 50 19 442 54 87 31 ## 6 99 50 390 34 20 330 102 86 20 ## 7 79 85 326 53 11 423 84 104 23 ## 8 127 64 347 40 16 333 81 104 24 ## 9 140 101 465 65 24 450 82 56 50 ## 10 130 55 483 59 14 542 90 103 53 ## 11 85 59 427 70 34 690 89 143 47 ## 12 103 50 465 85 14 701 93 81 35 ## 13 189 63 472 78 23 719 115 36 44 ## 14 139 71 451 59 11 806 80 91 42 ## 15 133 58 502 72 22 862 92 74 41 ## 타율 출루율 장타력 ops ## 1 0.2818317 0.3540291 0.4095309 0.7635600 ## 2 0.2663393 0.3471019 0.3921420 0.7392440 ## 3 0.2834244 0.3493936 0.4123862 0.7617798 ## 4 0.2564688 0.3442569 0.3725266 0.7167835 ## 5 0.2601582 0.3310580 0.3695119 0.7005699 ## 6 0.2675862 0.3425903 0.3600000 0.7025903 ## 7 0.2740344 0.3421119 0.3676346 0.7097465 ## 8 0.2702627 0.3394334 0.3770263 0.7164597 ## 9 0.2706262 0.3516507 0.3747515 0.7264022 ## 10 0.2884661 0.3656250 0.4166468 0.7822718 ## 11 0.2639261 0.3398496 0.3690100 0.7088596 ## 12 0.2695019 0.3505474 0.3648966 0.7154440 ## 13 0.2757827 0.3539895 0.3779926 0.7319821 ## 14 0.2819856 0.3551518 0.3861571 0.7413088 ## 15 0.2606668 0.3450245 0.3602238 0.7052483
이 코드를 그대로 실행하면 답이 15개라는 걸 어렵지 않게 확인할 수 있습니다. 자료가 너무 많아서 세기 어려울 때 직접 숫자를 출력하게 하려면 어떻게 해야 할까요?
개수를 세어주는 함수는 n()입니다. 우리는 이미 자료를 요약했습니다. 그렇다면 summarise() 함수를 쓰지 못할 이유가 없겠죠?
kbo %>%
filter(ops >= 0.7 & 홈런 < 70) %>%
summarise(n())
## n() ## 1 15
그렇다면 ops가 0.7 미만이거나 홈런이 70개 이하인 팀이 몇 팀인지 구하려면 어떻게 쓰면 될까요? 네 이번에는 '또는'을 활용하면 되니까 '|'를 쓰면 됩니다.
kbo %>%
filter(ops < 0.7 | 홈런 >= 70) %>%
summarise(n())
## n() ## 1 268
문3. 문2에서 뽑은 15개 팀 중 1982~1990년 사이 팀을 골라 각각 경기당 평균 득점과 도루 성공률을 구하시오.
답3. 일단 팀을 뽑을 때까지는 똑같으니까 filter() 부분까지는 똑같을 겁니다. 그다음 1982~1990년 사이에 속하는 팀을 골라야겠죠?
여러 가지 방법이 있을 수 있지만 (당장 뒤에서도 다른 방식으로 계산합니다.) 우리는 위에서 나온 c()를 써보도록 하겠습니다.
R에서는 ':'를 통해 연속해서 숫자를 표시할 수 있습니다. 예를 들어 콘솔에 1:5라고 쓰면 '[1] 1 2 3 4 5'라는 결과가 나옵니다.
마찬가지로 1982:1990이라고 쓰면 1982부터 1990까지 출력합니다. 이걸 한 데 묶어 두려면 c(1982:1990)으로 쓰면 그만입니다.
1982~1990년 사이 팀을 고르려면 연도가 이 범위 안에 들어있으면됩니다.
이럴 때는 '%in%'이라는 연산자를 씁니다. '연도 %in% c(1982:1990)'이라고 쓰면 되는 것.
(위에서 살펴본 것처럼 이때도 c를 쓰는 게 정석이지만 빼도 정상 작동합니다.)
이를 토대로 위 코드에서 filter를 이렇게 수정할 수 있습니다. 이번에도 그리고(and) 사례니까 '&' 기호를 써야겠죠?
kbo %>%
filter(ops >= 0.7 & 홈런 < 70 & 연도 %in% 1982:1990)
## 연도 팀 경기 타석 타수 득점 안타 X2루타 X3루타 홈런 총루타 타점 도루 ## 1 1982 MBC 80 3061 2686 419 757 124 12 65 1100 381 134 ## 2 1982 삼성 80 3043 2647 429 705 126 18 57 1038 374 147 ## 3 1982 OB 80 3098 2745 399 778 137 23 57 1132 362 106 ## 4 1982 롯데 80 3062 2628 353 674 112 8 59 979 325 83 ## 5 1985 OB 110 4189 3667 473 954 146 27 67 1355 432 107 ## 6 1987 롯데 108 4155 3625 432 970 161 27 40 1305 400 99 ## 7 1987 빙그레 108 4054 3547 410 972 144 22 48 1304 370 79 ## 8 1988 롯데 108 4095 3578 482 967 142 18 68 1349 446 127 ## 9 1990 LG 120 4661 4024 578 1089 156 40 61 1508 528 140 ## 도루실패 볼넷 몸에.맞는.공 고의사구 삼진 병살 희생번트 희생플라이 ## 1 60 268 47 20 316 56 32 27 ## 2 42 307 30 2 349 50 36 18 ## 3 61 247 41 22 254 35 46 18 ## 4 53 326 40 8 315 61 41 27 ## 5 76 354 50 19 442 54 87 31 ## 6 50 390 34 20 330 102 86 20 ## 7 85 326 53 11 423 84 104 23 ## 8 64 347 40 16 333 81 104 24 ## 9 101 465 65 24 450 82 56 50 ## 타율 출루율 장타력 ops ## 1 0.2818317 0.3540291 0.4095309 0.7635600 ## 2 0.2663393 0.3471019 0.3921420 0.7392440 ## 3 0.2834244 0.3493936 0.4123862 0.7617798 ## 4 0.2564688 0.3442569 0.3725266 0.7167835 ## 5 0.2601582 0.3310580 0.3695119 0.7005699 ## 6 0.2675862 0.3425903 0.3600000 0.7025903 ## 7 0.2740344 0.3421119 0.3676346 0.7097465 ## 8 0.2702627 0.3394334 0.3770263 0.7164597 ## 9 0.2706262 0.3516507 0.3747515 0.7264022
이제 남은 과제는 경기당 평균 득점과 도루 성공률을 구하는 것뿐입니다.
경기당 평균 득점은 '득점 ÷ 경기 (숫자)'로 계산하면 되고, 도루 성공률은 '도루 ÷ (도루 + 도루실패)로 계산합니다.
그러면 필요한 변수(열)는 경기, 득점, 도루, 도루실패가 됩니다 = select(경기, 득점, 도루, 도루실패).
이걸 다시 공식에 따라 계산해서 붙여 넣으면 되니까 mutate(평균득점 = 득점/경기, 도루성공률=도루/(도루+도루실패))라고 정리할 수 있습니다.
연도랑 팀도 같이 나오게 써볼까요?
kbo %>%
filter(ops >= 0.7 & 홈런 < 70 & 연도 %in% 1982:1990) %>%
select(연도, 팀, 경기, 득점, 도루, 도루실패) %>%
mutate(평균득점 = 득점/경기, 도루성공률=도루/(도루+도루실패))
## 연도 팀 경기 득점 도루 도루실패 평균득점 도루성공률 ## 1 1982 MBC 80 419 134 60 5.237500 0.6907216 ## 2 1982 삼성 80 429 147 42 5.362500 0.7777778 ## 3 1982 OB 80 399 106 61 4.987500 0.6347305 ## 4 1982 롯데 80 353 83 53 4.412500 0.6102941 ## 5 1985 OB 110 473 107 76 4.300000 0.5846995 ## 6 1987 롯데 108 432 99 50 4.000000 0.6644295 ## 7 1987 빙그레 108 410 79 85 3.796296 0.4817073 ## 8 1988 롯데 108 482 127 64 4.462963 0.6649215 ## 9 1990 LG 120 578 140 101 4.816667 0.5809129
문4. 1982~1990년, 1991~2000년, 2001~2010년, 2011~2017년 평균 희생번트 숫자를 구하시오.
답4. 이번에는 다른 방법으로 그룹을 구분해 보도록 하겠습니다. 여러 그룹으로 자료를 분류할 때는 그룹 이름으로 새로운 변수(열)을 만들어 사용하면 편합니다.
그러니까 어떤 행이 △1982~1990년 △1991~2000년 △2001~2010년 △2011~2017년에 각각 속한다는 걸 알려주는 이름 변수를 추가하는 겁니다. 예를 들어 이 네 개 그룹에 각각 A~D라는 이름을 붙일 수 있을 겁니다.
이 이름을 붙여주려면 조건문이라는 걸 쓰면 됩니다. '연도' 변수가 1982~1990에 속해 있다면 '그룹'이라는 열에 A라는 값을 추가하는 방식입니다.
R에서 조건문을 쓸 때는 if()라는 함수를 쓰는 게 제일 일반적입니다. 이런 구조입니다.
if(연도<=1990){
그룹 <- "A"
} else{
if(연도<=2000){
그룹 <- "B"
} else{
if(연도<=2010){
그룹 <- "C"
}
else{
그룹 <- "D"
}}}
if와 else를 계속 반복하니까 좀 지겹습니다.
그래서 R에는 ifelse()라는 함수도 들어 있습니다.
ifelse()는 MS 엑셀에서 if 함수를 활용할 때와 같은 방식입니다. 이 코드는 이렇게 쓸 수 있습니다.
ifelse(연도<=1990, 그룹 <-"A",
ifelse(연도<=2000, 그룹 <- "B",
ifelse(연도<=2010, 그룹 <- "C", 그룹 <- "D")))
우리는 이 그룹을 새로운 열에 추가하기로 했으니까 mutate()를 써야겠죠?
그다음 파이프로 연결하면 이렇게 됩니다.
kbo %>% mutate(그룹 = ifelse(연도<=1990, "A",
ifelse(연도<=2000, "B",
ifelse(연도<=2010, "C", "D"))))
이제 그룹으로 묶고 평균을 내면 됩니다. group_by(), summarise()를 쓰면 되겠죠?
kbo %>% mutate(그룹 = ifelse(연도<=1990, "A",
ifelse(연도<=2000, "B",
ifelse(연도<=2010, "C", "D")))) %>%
group_by(그룹) %>%
summarise(평균희생번트=mean(희생번트))
## # A tibble: 4 x 2 ## 그룹 평균희생번트 ## <chr> <dbl> ## 1 A 71.1 ## 2 B 83.7 ## 3 C 83.3 ## 4 D 77.8
문5. 통산 병살타가 가장 많은 세 개 팀을 고르시오.
답5. 마지막이라 쉬운 문제로 준비했습니다. 답은 아래와 같습니다.
kbo %>% group_by(팀) %>%
summarise(병살=sum(병살)) %>%
arrange(desc(병살)) %>%
head(3)
## # A tibble: 3 x 2 ## 팀 병살 ## <fct> <int> ## 1 삼성 3392 ## 2 롯데 3273 ## 3 LG 2687
그냥 팀별로 그루핑을 한 다음 병살타 합계를 요약하고 내림차순으로 그 결과를 정렬해서 그 가운데 제일 위에 나온 세 개만 뽑으면 그만입니다.
지금까지 쓰고 보니 결국 타석과 고의사구 변수는 한 번도 사용하지 않았습니다.
두 변수를 사용하면 '타석당 고의사구가 가장 높은 팀은 어디인가?', '타석당 고의사구가 가장 높았던 시즌은?' 같은 문제를 만들어 풀 수 있을 겁니다.
그리고 위에서 사용한 함수 여섯 가지가 dplyr 패키지 기능 전부인 것도 아닙니다. 기본 원리를 공부하려고 제일 많이 쓰는 여섯 가지만 소개해 드린 겁니다.
나머지 함수는 아래 있는 dplyr 커닝 페이퍼를 통해 사용법을 살펴보시면 됩니다. (내려 받으시면 큰 크기로 보실 수 있습니다. 이미지 두 장입니다.)
혹시 이 포스트 내용 중 이해가 가지 않거나 잘못된 게 있으면 댓글 등을 통해 언제든 알려주세요. 같이 공부하면서 고쳐나가도록 하겠습니다.
댓글,