2015년 4월 23일 목요일

[하루에 한 R] 특정 조건에 맞는 row만 출력하기

어제의 포스팅에서 다루었던 파일(data3.txt)을 이용하여 R의 또 다른 활용 방법을 살펴보자. 특정 조건을 만족하는 row만을 출력해 보는 것이다.
$ cat data3.txt
Nation,Pop.density, Area, Population
UK,255.6,243610,62262000
France,111,547030,63601002
Germany,233,357021,81799600
Korea,513,100210,51098531
N.Korea,200,120538,25051706
Japan,337,377873,127387000

 첫 줄의 요소 수는 나머지 라인의 요소 수와 같다. 이를 감안하여 R에서 데이터 파일을 읽어들이자. 이렇게 읽어들인 data 오브젝트는 list이다. mode(list)라고 실행하면 금방 알 수 있다.
> data = read.table("data3.txt",sep=",",header=TRUE,row.name=1)
> data
        Pop.density   Area Population
UK            255.6 243610   62262000
France        111.0 547030   63601002
Germany       233.0 357021   81799600
Korea         513.0 100210   51098531
N.Korea       200.0 120538   25051706
Japan         337.0 377873  127387000
오늘의 과제는 인구밀도(Pop.density)가 300보다 작은 널널한 나라를 찾아보자는 것이다.

방법 1. 슬라이싱을 절묘하게 이용하기

마치 암호같지만 잘 살펴보면 그 작동 원리를 이해할 수 있다. 두 가지 방법을 나열해 보겠다.
> data[, "Pop.density"] < 300
[1]  TRUE  TRUE  TRUE FALSE  TRUE FALSE
> data[data[, "Pop.density"] < 300, ]
        Pop.density   Area Population
UK            255.6 243610   62262000
France        111.0 547030   63601002
Germany       233.0 357021   81799600
N.Korea       200.0 120538   25051706

> data$Pop.density < 300
[1]  TRUE  TRUE  TRUE FALSE  TRUE FALSE
> data[data$Pop.density < 300, ]
        Pop.density   Area Population
UK            255.6 243610   62262000
France        111.0 547030   63601002
Germany       233.0 357021   81799600
N.Korea       200.0 120538   25051706
여기에서 R 코드의 가장 아름다운 면이 드러난다. 바로 [, -1]과 같이 데이터를 '쳐 내는' 것이다. 그러면 위 코드에 대한 설명을 해 보겠다. 첫번째 사례에서는 data[, something] < 300이라는 조작을 했다. [ ] 안의 두번째 위치이니 something에 해당하는 컬럼에 대해서 조건을 만족하는지를 모든 row에 대해서 시험하는 것이다. 따라서 반환되는 값은 TRUE FALSE... 와 같다. 이를 전체 데이터에 대해서 다시 첫번째 인자로 넣었으니 이 조건을 만족하는 row를 내놓으라는 뜻이 된다.

조건을 하나 더 붙여보자. 인구밀도는 300보다 작은데다가 면적은 350000을 넘는 덩치가 크고도 널널한 나라를 찾아보자. & 혹은 |를 쓰면 된다. Perl에서 && 및 || 연산자를 떠올리면 된다. 정확히 같은 것과 같지 않은 것도 뽑을 수 있다. 그건 각자 알아보라.

> data$Pop.density < 300 & data$Area > 350000
[1] FALSE  TRUE  TRUE FALSE FALSE FALSE
> data[data$Pop.density < 300 & data$Area > 350000, ]
        Pop.density   Area Population
France          111 547030   63601002
Germany         233 357021   81799600

방법 2. 데이터프레임으로 전환한 뒤 subset() 함수 적용하기
> data.frame = as.data.frame(data)
> subset(data.frame, Pop.density < 300)
        Pop.density   Area Population
UK            255.6 243610   62262000
France        111.0 547030   63601002
Germany       233.0 357021   81799600
N.Korea       200.0 120538   25051706
조건을 여러개 다는 것도 위에서 살펴본 것과 마찬가지 방법으로 가능하다. 
> subset(data.frame, Pop.density < 300 & Area > 350000)
        Pop.density   Area Population
France          111 547030   63601002
Germany         233 357021   81799600
팁 하나: 출력물을 파일로 보내고 싶다.... sink() 함수 활용하기

출력물이 한 화면을 넘어가면 이를 일일이 긁어서 페이스트를 할 수는 없다. 다음과 같이 해 보라. result라는 파일에 화면 출력물이 고스란히 저장된다. 다시 출력을 화면으로 되돌리는 것은 인수 없이 sink()를 실행한 이후이다. 공백은 탭 형태로 저장된다. 
> sink("result")
> subset(data.frame, Pop.density < 300 & Area > 350000)
> sink()
정말 멋지지 않은가? 다음에는 heatmap을 그리는 방법에 대해서 포스팅하고자 한다.

[업데이트] 2019년 2월 8일에 추가한 글

슬라이싱(slicing)의 정확한 의미는 무엇인가? 칼로 얇게 썰어내듯이 데이터 프레임의 어떤 부분(주로 row)를 잘라서 취하는 것을 일반적으로 의미하는가, 혹은 dplyr 패키지의 slice() 함수를 사용하는 것만을 의미하는가? Subsetting에 대해서도 똑같이 이야기할 수 있다. slice() 함수의 기능은 'select rows by position'이라고 하였다. 그렇다면 row를 논리적 조건에 의해 골라내는 것은 슬라이싱이라고 불러서는 안될 것이다. subset() 함수는 R의 기본 패키지에 포함되어 있다.


댓글 없음: