데이터를 분석하려면 데이터를 분석에 적절한 형식으로 변환하는 전처리가 필요하다. 또한 기본적인 분석을 위해서도 데이터를 요약하는 작업이 필요하다. 이 장에서는 정돈 형식의 데이터 프레임을 변환하는 방법을 배운다. 정돈 데이터란 그림 7.1처럼 다음의 조건을 만족하는 데이터 행렬(R에서는 데이터 프레임)의 형식을 의미한다.
Figure 7.1: 정돈 데이터 현실에서 만나는 많은 데이터가 정돈 데이터 형식이지만, 그렇지 않은 데이터도 자주 볼 수 있다. 그림 7.2의 왼쪽 데이터는 어떤 가상의 감염병에 대해 세 나라의 발생 사례를 월별로 정리한 데이터이다. 이 데이터는 감염 사례라는 변수와 관련된 데이터가 3개의 열에 흩어져 있으므로 비정돈 형식이다. 월별, 년도별 매출처럼 시계열 데이터는 종종 이런 형식으로 데이터가 표현된다. 이러한 방식의 표현은 데이터를 매우 압축적인 방식으로 표현할 수 있고 같은 시간대의 데이터를 비교하기 쉬운 장점이 있다. 그림 7.2의 오른쪽 데이터는 왼쪽 데이터를 정돈 형식으로 변환한 결과이다. 이러한 변환을 하는 방법에 대해서는 9 장에서 다룰 것이다. Figure 7.2: 비정돈 데이터 그림 7.2를 보면 정돈 형식 데이터가 오히려 비효율적인 방식으로 보이며, 데이터를 한 눈에 비교하기도 어려워 보인다. 그럼에도 정돈 형식의 데이터를 사용하는 이유는 표준화된 데이터 변환 작업을 하기 위해서이다. 한 행이 하나의 관측 대상을, 한 열이 하나의 변수를, 한 셀이 한 값을 나타낸다는 가정이 성립하면, 데이터 변환이나 데이터를 이용한 그래픽 작업을 데이터의 내용에 무관하게 항상 일정한 형식으로 수행할 수 있다. 04 패키지는 정돈 데이터 패러다임을 따른 R 패키지들을 한번에 설치하고 적재할 수 있도록 돕는 패키지이다. 04 패키지를 설치하려면 다음 명령을 실행하면 된다. 패키지의 이름은 문자열이므로 따옴표 안에 기술해야 한다.또는 RStudio의 Packages 탭에서 [Install]을 클릭한 후 tidyverse라고 입력을 하면 된다. 패키지 설치는 한 번만 수행하면 된다. 04 패키지가 설치되었으면 패키지를 사용할 때마다 네임스페이스를 적재하고 검색 리스트에 패키지를 포함하는 작업이 필요하다. 다음은 04 패키지를 적재하는 명령어이다. 이번에는 패키지 이름에 따옴표가 없음에 주의한다.
앞의 명령을 실행하면 정돈 데이터 패러다임을 따르는 여러 개의 패키지가 동시에 적재된다. 그리고 R 기본 패키지와 정돈 데이터 패키지 중에서 이름이 충돌이 나는 것에 대해 보고를 한다. 만약 R 기본 패키지에서 이 함수를 사용하는 경우에는 08 형식으로만 사용할 수 있다. 자세한 내용은 R 관련 책을 참조하기 바란다.정돈 데이터의 변환에는 04 패키지가 포함하고 있는 10 패키지가 이용된다. 앞에서 04를 적재하였으면 이미 10이 적재되어 있으므로 다시 적재할 필요가 없다.정돈 데이터의 변환은 크게 5가지 변환 작업이 있다. 그리고 위의 작업은 13 함수와 같이 사용되어 전체 데이터에서 작업이 수행되는 것이 아니라 관측(대상)의 그룹별로 수행되도록 조정할 수 있다. 다음 그림은 정돈 데이터 변환 함수에 의한 변환 결과를 예시하고 있다.이 함수들은 모두 다음과 같은 인터페이스를 가지고 있다.
일반적으로 데이터의 변환 작업은 위의 6가지 작업이 여러 차례 순서대로 결합하여 진행된다. 앞으로 볼 10 패키지의 함수들이 수행하는 작업은 R에서 제공하는 기본 함수로도 수행될 수 있다. 특히 15, 16, 17, 18 함수의 작업은 R 데이터프레임의 필터링 기능을 사용하면 대체할 수 있으며, 19와 13 함수의 작업은 21, 22 등을 사용하면 대체할 수 있다. 그럼에도 불구하고 복잡한 데이터 변환을 수행할 때 R의 기본 기능보다는 10 패키지의 함수들이 선호되는 이유는 다음과 같다.
이 장에서는 28 패키지에서 제공하는 29 데이터를 이용하여 정돈 데이터를 변환하는 함수를 설명한다.다음 명령을 이용하여 29 데이터를 출력해 보자. 화면의 크기에 따라 출력되는 내용이 책과는 조금 다를 수 있다.
29는 1999년과 2008년에 미국 EPA에서 조사하여 발표한 자동차 주요 모델별 연비 데이터이다. 데이터는 234 개의 행이 있으며, 각 행은 다음과 같은 변수로 구성되어 있다.
선택 조건이 하나인 경우 다음 형식으로 15를 사용한다.
’데이터프레임’에는 15를 적용할 데이터 프레임을 ’조건’에는 행 선택 조건을 기술한다. ’조건’은 논리값 벡터이어야 한다. 많은 경우 ’조건’은 다음처럼 변수와 어떤 값을 비교연산자로 비교한다. 다음 예에서 보는 것처럼 10 패키지의 함수들은 첫번째 인수로 데이터프레임을 지정한 후, 나머지 부분에서 그 데이터프레임의 열을 변수처럼 사용할 수 있다.
조건을 서술할 때 자주 틀리는 부분이 등호 기호로 35를 사용하는 것이다. R에서 두 값이 같은지를 비교할 때는 36를 사용한다.다음처럼 조건에 사용되는 변수에 대해 연산을 수행한 후에 그 결과를 비교할 수도 있다.
두 개 이상의 조건을 모두 만족하는 행만 뽑아내려면 다음의 문법을 사용한다.
다음은 현대에서 생산한 차 중 도심 연비가 20 마일 이상인 차만 추출한 결과이다. 0 1앞의 조건에서 배기량이 2.4 이상인 차만 추출해 보자. 2 3지금까지는 하나의 조건이나 여러 조건을 동시에 만족하는 행을 추출하는 방법을 보았다. 어떤 경우에는 여러 조건 중 하나라도 만족하면 그 행을 추출해야 할 경우가 있다. 이러한 경우에는 2 장에서 배운 논리 연산자를 이용하여 복합 조건을 만들어야 한다. 다음은 OR 연자자인 37를 이용하여 두 조건 중 하나만 만족하여도 행이 추출되도록 하였다. 4 5만약 위의 결과에서 2008년도 데이터만 추출하고 싶다면 어떻게 해야 할까? 다음처럼 두 조건식을 사용하여 첫 번째 조건과 두 번째 조건을 모두 만족하는 결과만 추출할 수도 있고, 하나의 조건식에 AND 연산자인 38를 사용하여 복합 조건식을 사용하여 추출할 수도 있다. 6 7 8 7단, 복합 조건식에서 AND 연산이 OR 연산보다 우선순위가 있으므로 괄호를 사용하여 연산의 순서가 제대로 되도록 하여야 한다. 괄호가 없으면 AND가 수행된 후 OR가 수행되어 모든 소타나 자동차의 결과가 추출되었음을 볼 수 있다. 0 1만약 조사 년도가 2008년이고, 고속도로 연비가 30 이상이면서, 자동차 모델이 sonata 또는 corolla 또는 jetta인 행을 찾고자 한다면 어떻게 해야 할까? 앞에서 배운 복잡 조건문을 사용하여 다음처럼 수행할 수 있을 것이다. 2 3위의 명령은 39 연산자를 사용하면 좀 더 간단해 질 수 있다. 39 연산자는 어떤 값이 벡터의 요소 중에 하나인지를 판별해 준다. 4 5 5 4그러므로 앞에서 수행한 명령은 다음처럼 수행할 수도 있다. 8 3 16는 다음 문법을 사용하여 행을 정렬한다. 0 15와 마찬가지로 첫 번재 인수로 정렬할 데이터 프레임을 전달 받는다. 그리고 두번재 인수부터 정렬의 기준이 되는 변수를 차례로 기술한다. 첫 번째 기준 변수의 값이 같으면, 두 번째 기준 변수를, 두 번째 기준 변수의 값까지 같으면 그 다음 변수를 기준으로 차례로 순서를 결정하여 정렬을 수행한다.다음은 2008년도 현대의 자동차 모델만 15론 선택하여 44라는 변수에 저장한 후, 이 데이터에 대하여 여러 조건으로 정렬을 수행해본 예이다. 1 2 3 4 5앞의 예에서 16는 수치 변수는 올림차순으로 문자 변수는 알파벳 순으로 정렬하는 것을 볼 수 있다. 만약 위의 예에서 내림차순으로, 또는 알파벳 역순으로 정렬을 하고 싶으면 어떻게 하여야 할까? 10 패키지는 47를 이용하면 된다. 6 7 8 47가 적용된 변수만 내림차순을 기준으로 정렬을 하는 것을 볼 수 있다. 17 함수는 다음처럼 변수 이름을 일일이 나열하여 원하는 열을 선택할 수 있다. R의 기본 문법을 알고 있는 사람들은 데이터 프레임의 인덱싱에서처럼 문자열로 이름을 나열하는 것이 아니라 변수를 사용하듯 따옴표 없이 이름을 나열하는 것에 주의한다. 9 0 17 함수는 다음처럼 변수 이름으로 선택할 변수의 범위를 지정할 수 있다. 1 2 3반대로 다음처럼 변수 이름으로 선택하지 않을 변수의 범위를 지정할 수 있다. 4 5 6 7 17 함수는 R의 기본 인덱싱(필터링)처럼 선택할 열의 위치를 자연수 인덱스 벡터로, 선택하지 않을 열은 음의 정수 인덱스 벡터로 지정할 수도 있다. 8 9 0 1 2 10 패키지는 다양한 형태로 변수를 선택할 수 있도록 다음의 변수 이름 매칭 함수를 제공한다. 이러한 함수는 변수의 수가 많을 때 매우 유용하다.
3 17 함수에 59 함수를 사용하면 해당 조건에 맞는 열만 매칭하여 선택할 수 있다. 59 함수는 유일한 인수로 함수를 입력받는데, 이 함수는 논리값을 반환하는 함수여야 하며, 59 함수는 각 열에 이 함수를 적용한다. 17 함수는 59의 결과가 64인 열만 선택한다. 59 함수가 주로 사용되는 곳은 데이터 형식에 따라 열을 선택할 때이다. 66로 시작하는 함수들은 어떤 객체가 특정 형식인지를 테스트 한다. 다음 예는 59와 68 함수를 사용하여 문자열인 열만 선택한 것이다. 4다음 예는 무기명 함수를 이용하여 열이 수치 벡터이고, 열의 평균이 10 이상인 열만 출력한 것이다. 5또는 다음처럼 purr 형식의 수식으로 무기명 함수를 좀 더 간략하게 정의할 수도 있다. 6 17 함수에서 변수 이름을 지정할 때, 70 형식으로 지정하면 변수의 이름을 바꿀 수 있다. 7 8만약 전체 데이터를 유지한 상태에서 변수 이름만 변경하려면, 71 함수를 이용한다. 문법은 17와 같다. 9 0 17 함수는 나열된 변수의 순서에 따라 새롭게 만들어진 데이터 프레임의 변수의 순서를 조정한다. 1 2이러한 성질과 74 함수를 이용하면 변수의 순서를 쉽게 바꿀 수 있다. 74은 이미 선택된 변수를 제외한 나머지 변수를 의미한다. 3 18는 기존 변수를 이용하여 새로운 변수를 만들어 데이터 프레임의 가장 마지막 열로 추가한다. 4다음은 도심 연비와 고속도로 연비의 합과, 평균, 그리고 고속도로 대비 도심 연비의 비율(%)을 계산하여 새로운 열을 만든 예이다. 5 6 7 8 9만약 새롭게 만들어진 변수만 데이터에 남기려면 18 대신 78를 사용한다. 문법은 두 함수가 동일하다. 0 1새로운 변수를 생성할 때, 기존 변수와 관련된 수치, 논리, 문자열 연산을 수행할 수 있다. 다음처럼 제조사와 모델을 하나로 합쳐서 새로운 변수를 만들수도 있고, 배기량이 3 이상인지 여부를 나타내는 변수도 만들 수 있다. 2 3아울러 다음 함수가 새로운 변수를 만들 때 자주 사용된다. 다음의 가상의 상점의 월별 매출 데이터를 사용하여 위에서 설명한 함수의 기능을 살펴보자. 4 5 6 7다음은 앞의 예에서 만든 b라는 데이터프레임에 일련번호를 사용하여 id라는 열을 추가한 사례이다. 8 9 19 함수는 데이터프레임을 하나의 행으로 요약한다. 하나의 행으로 요약하기 위하여 변수의 모든 값을 하나의 값으로 통계요약하는 함수를 주로 이용한다. 대표적인 통계요약 함수는 다음과 같다.
다음은 도심 연비의 데이터 수, 평균, 중위수, 최소값, 최대값을 구한 결과이다. 0다음처럼 여러 변수에 대하여 통계 요약할 수도 있다. 1앞의 예에서 우리는 도심 연비와 고속도로 연비 열에 대해 동일한 통계요약 함수를 적용하였다. 동일한 통계요약 함수를 적용할 열이 한두 개이면 앞의 예처럼 일일이 기술해주면 되지만, 적용해야 할 열이 많아지면 이를 일일이 기술하는 것은 번잡할 뿐만 아니라 오류의 발생 가능성을 높이고 나중에 코드를 변경하기 어렵게 만든다. 89 함수는 17처럼 열을 선택하여 동일한 함수를 적용할 수 있게 해준다. 89 함수는 두 개의 주요 인수를 가지고 있다.
89 함수는 19 함수와 함께 자주 사용되는데 다음처럼 사용된다. 2여러 함수를 함께 적용하려면 함수를 리스트로 묶어서 94 인수로 전달한다. 이 때 리스트의 요소의 이름을 부여하면 열이름과 해당 요소의 이름으로 결과 열의 이름이 생성된다. 3결과 열의 이름을 다른 형태로 지정하고 싶으면 98 인수에 원하는 형식을 함수 이름을 나타내는 99과 열의 이름을 나타내는 00을 사용하여 설정할 수 있다. 다음은 함수 이름 후에 01가 나온 후 열 이름이 나오도록 한 것이다. 4만약 지금처럼 적용되는 열을 기준으로 정렬되는 것이 아니라 함수 별로 정렬되어 결과가 나오게 하고 싶으면, 89 함수를 각 함수 별로 적용을 한다. 이 때 서로 열 이름이 충돌이 나지 않도록 03 인수를 설정해 준다. 5다음 예는 모든 수치 열에 대하여 표준편차를 구한 것이다. 6 7 13 함수는 기준이 되는 변수의 구분되는 값에 따라 데이터를 그룹화한다. 그룹화된 결과를 19 함수에 전달하면 그룹별로 요약된 결과를 출력한다. 8그룹화된 결과를 출력해 보면, 원 데이터인 06와 같아보이는데, 출력시 model 변수로 그룹화 되어 있다는 것이 같이 출력된다. 9변수를 여러 개를 조합하여 그룹화를 할 수도 있다. 0 1여러 변수로 그룹화를 하면 19 함수는 그룹별로 하나의 행만 생성이 되었으면 결과에서 마지막 그룹을 제거한다. 위의 결과에서는 model과 cyl의 값의 조합에 대하여 하나의 행만 생성되었으므로, 마지막 그룹 변수인 cyl와 관련된 그룹은 사라지고, model과 관련된 그룹만 남는다. 출력된 결과와 메시지에서 이를 확인할 수 있다. 19 함수의 09 인수를 사용하면 19 후에 그룹을 유지할지, 모두 없앨지 등을 조정할 수 있다. 관심있는 독자는 19 함수의 도움말을 참조하기 바란다. 13는 19와 함께 자주 사용되지만, 18나 15 등의 다른 10 함수와 함께 사용될 수 있다.다음은 18로 전체 대이터에 대하여 고속도로 연비 순으로 순위를 매기는 것과, 18와 함께 사용하여 모델별로 고속도로 연비의 순위를 매긴 것을 비교하여 보여 주고 있다. 2 3 29 데이터에서 조사 연도와 모델 별로 데이터 수와 도심 연비의 평균을 구한 후, 평균이 22 이상인 모델로 이루어진 행을 추출하려고 한다. 이를 수행하려면 다음처럼 변수를 이용하여 결과를 차례로 전달하거나, 함수를 결합하여 한 문장에 사용하여야 한다. 0 5 0 5전자는 불피요하게 중간 결과를 저장할 변수를 만들어야 하고, 후자는 복잡하여 이 명령이 무엇을 하는 명령어인지 쉽게 파악하기 힘들다. 또한 중첩된 괄호 때문에 오류가 발생하기 쉽다. 파이프 연산자는 데이터 변환이 여러 단계를 거칠 때 불필요한 변수의 생성 없이도 함수 간에 중간 데이터를 전달할 수 있게 해 준다. 파이프 연산자는 앞의 함수의 결과를 뒤 함수의 첫 번째 인수로 전달해 준다. 파이프 연산자를 사용할 때는 그러므로 첫 번째 인수는 생략하여 기술한다. 파이프 연산자로는 20 패키지가 제공하는 21 연산자를 사용할 수도 있고, R 4.1.0 버전부터 도입된 기본 기능에 포함된 22 연산자를 사용할 수도 있다. 여기서는 R 버전이 낮은 사용자에게도 동일하게 적용될 수 있도록 21 연산자를 사용하도록 한다. 이 연산자는 04 패키지를 적재하였으면 사용할 수 있다.다음은 앞의 예와 동일한 예를 파이프 연산자를 사용하여 수행한 결과이다. 0 5불필요하게 데이터를 기술하는 부분이 사라져서 각 단계에서 수행하는 작업이 무엇인지 명확하게 들어나고 불필요한 중간 변수를 만들지 않아도 되므로 파이프 연산자는 매우 편리하다. 그런데 파이프 연산자를 사용하려면 앞의 함수의 결과가 뒤의 함수의 첫 인수로 사용하기 적절한 형태이어야 한다. 10 패키지의 주요 함수들은 정돈 데이터 형식으로 데이터의 결과를 반환하고, 첫 인수가 정돈 데이터 형식의 데이터로 간주한다.파이프 연산자를 사용할 때 주의할 점은 여러 줄로 명령을 기술할 때, 파이프 연산자로 중간 문장이 종료되어야 한다는 것이다. 그래야 아직 문장이 완료되지 않았다는 것을 이해하여 다음 단계의 명령이 입력되기를 기다린다. 다음처럼 기술하면 R은 명령 입력이 중간에 완료된 것으로 보고 잘못된 결과를 출력한다. 00 01 21 연산자 이외에도 연산 결과를 출력도 하고 결과를 반환하고 싶을 때 사용하는 27 연산자, 입력된 객체에 결과를 재할당하고 싶을 때 사용하는 28 연산자 등도 있으니 관심있는 독자는 도움말을 살펴보기 바란다. |