본문 바로가기
R

[R.아르] 찾아바꾸기(2) lapply() / if()

by LightBlogger 2016. 9. 26.

apply() 함수는 연산을 행 또는 열 단위로 적용해 주는 함수다.


예를 들어 다음과 같은 x에서 우리는 1열의 합을 구할 수 있을 것이고



마찬가지로 2행의 합도 구할 수 있을 것이다.



각 행, 혹은 각 열의 합을 구하려면 어떻게 할까?


이럴 때 apply() 함수를 사용한다.


apply(데이터, 행 또는 열, 적용할 함수) 와 같이 적는다.



apply() 중간의 '1' 은 행 방향으로 함수를 적용하라는 의미이다.


2는 열 방향으로 함수를 적용한다.



이전에 2016/09/26 - [R] - [R.아르] 찾아바꾸기 gsub() 에서 본 대로 gsub()은 한 번에 한 벡터에만 적용 가능한 한계가 있으므로


gsub()과 apply()를 조합하면 전체 데이터프레임에서 찾아바꾸기를 실행할 수 있다고 추론할 수 있다.


옳은 생각이지만, 정확히는 lapply()나 sapply를 사용해야 한다.


apply()는 기본적으로 매트릭스matrix를 인자로 받는 함수로서, 데이터프레임에 적용할 때 원치않는 결과를 내는 경우가 있다.


sapply()나 lapply()는 데이터프레임을 인자로 받을 수 있다. 


일단 sapply() 부터 알아보자. 


예를 들어 다음과 같은 데이터프레임 x에서



sapply()를 이용해 각 열의 클래스를 한 번에 파악할 수 있다.



apply() 처럼 열 방향, 행 방향을 지정할 필요는 없으며, 


자동으로 열 단위로 함수를 적용하는 것을 볼 수 있다.


만일 똑같은 작업을 apply()를 이용해 수행한다면



위와 같이 모든 클래스에 캐릭터를 반환한다.


이는 apply()가 매트릭스를 인자로 받는 함수로서 


x를 자동으로 매트릭스로 변환한 후 apply()를 적용하기 때문이다.


매트릭스는 데이터프레임과 달리, 포함된 모든 요소의 자료형class이 동일하다는 특징이 있다.


때문에 apply()는 x를 numeric과 character를 모두 아우를 수 있는 character 자료형을 가진 matrix로 간주하고


함수를 적용하는 것이다.



설명이 길었지만, 그러므로 데이터 프레임의 각 열의 특성을 살린 채 함수를 적용하려면


sapply()나 lapply()를 사용해야 한다.


(참고로 sapply()의 s는 simplify, lapply() 의 l은 list를 의미한다고 한다.)



그럼, 아래와 같은 x에 sapply() 와 gsub()을 이용하여 a를 A로 바꾸어 보자.


아까 sapply()의 마지막 부분, class나 sum이 들어가는 부분이 '적용할 함수'를 적는 부분인데,


우리가 사용할 gsub() 같이 인자가 여러개인 경우는 먼저 function(x) 라고 선언해 주고 그 뒤에 함수 내용을 적으면 된다.



훌륭히 적용된 것을 볼 수 있다. 다만,



y자체의 클래스는 matrix로 반환되었으며, 안의 요소는 모두 character인 것을 볼 수 있다.


이는 sapply() 가 결과값으로 벡터, 혹은 매트릭스를 반환하는 함수이기 때문이다.


위에서 설명한 바와 같이 매트릭스는 모든 요소가 동일한 클래스를 갖는다.


var와 var2의 numeric 클래스까지 유지하려면 lapply()를 사용해야 한다.


lapply()는 sapply()와 동일하나, 결과로 리스트를 반환한다.



각각 독립적인 벡터를 아우르는 리스트를 반환하는 것을 볼 수 있다.


그러나 여전히 모든 벡터가 캐릭터 벡터인데...?


이것은 lapply() 때문이 아니라 gsub() 자체가 캐릭터 벡터를 결과물로 반환하기 때문이다.


즉, var와 var2의 클래스를 유지하기 위해서는 numeric 클래스일 경우 아예 gsub()을 적용하지 않도록 명령을 내려야 한다.


if() 가 이런 역할을 해 줄 수 있다. 



캐릭터나 팩터의 경우에만 gsub()을 적용하고, 아닌 경우에는 그대로 남겨두라는 if()를 삽입하였다.


name열만 정확히 gsub()이 적용된 것을 볼 수 있다.


마지막으로 데이터프레임 형태로 보겠다고 선언하면 동일한 모양으로 출력된다.



조금 복잡해 보이지만, 완성된 함수는 다음과 같다.


as.data.frame(lapply(x, function(x) if(is.character(x)|is.factor(x)) gsub("a", "A", x) else(x)))





반응형

댓글