지난번 포스팅에서는 벡터공간(vector space), 벡터 부분공간(vector subspace), 생성공간(span), 차원(dimension)에 대해서 알아보았습니다.

 

이번 포스팅에서는 선형사상(linear map)에 대해서 소개하겠습니다.

선형사상(linear map)은 두 벡터공간 사이에 정의되는 사상(베낄 사 寫 형상 상 像, map) 가운데 벡터공간의 성질을 보존하는, 즉 선형성을 갖는 함수를 말합니다. 선형변환(linear transform) 이라고도 합니다.

 

두 벡터공간 V와 W에 대하여 선형사상 f : V -> W 라고 하면, 아래의 두가지 조건(벡터의 합, 스칼라 곱 조건)을 만족하는 사상입니다.

 

[선형성(linearity) 조건] 

(1) 벡터의 합 조건 : f(v1 + v2) = f(v1) + f(v2)

(2) 스칼라 곱 조건 : f(cv) = cf(v), 단 c는 임의의 실수

 

 

 

 

사상 f가 R^n에서 R^m으로의 선형사상인 경우에, f를 m*n 행렬에 의해 정해지는 R^n에서 R^m으로의 선형사상이라고 합니다.

 

 

 

 

벡터공간 R^n과 R^m 사이의 모든 선형사상(linear map)은 행렬(matrix)을 이용해서 나타낼 수 있으며, 또 행렬은 선형일차연립방정식(system of linear equations)으로 나타낼 수 있습니다. 유한차원 벡터공간 사이의 선형 연산을 연구하고 싶다면, 행렬을 보면 된다는 뜻입니다. 

 

선형일차연립방정식 - 행렬 - 선형사상의 관계를 아래의 3개의 x변수와 2개의 y변수를 가지는 선형일차연립방정식, 2*3 행렬, R^3에서 R^2로의 선형사상 f 의 예를 들어보겠습니다.

 

 

 

 

 

 

m*n 행렬에 의해 R^n에서 R^m 으로의 선형사상의 간단한 몇 가지 경우를 나타내보면 아래와 같습니다.

m*n 행렬의 m, n 순서와 R^n에서 R^m으로의 선형사상의 n, m 순서에 유의하시기 바랍니다.

 

 

 

 

다음번 포스팅에서는 핵(kernel), 상공간(image), 차원정리(Dimension Theorem)에 대해서 알아보겠습니다.

 

이번 포스팅이 도움이 되었다면 아래의 공감 ♡ 꾸욱~ 눌러주세요. ^^

 

 

 

 

728x90
반응형
Posted by Rfriend
,

지난번 포스팅에서 선형독립(linearly independent)과 선형종속(linearly dependent), 기저(base, basis)에 대해서 알아보았습니다

 

이번 포스팅에서는 벡터공간(vector space), 벡터 부분공간(vector subspace), 생성공간(span, space spanned by), 차원(dimension)에 대해서 소개하겠습니다. 이들은 선형대수를 공부하는데 있어서 기본개념이 되며, 기저와 차원을 이해하기 위해서는 부분공간을 알고 있어야 합니다.

 

기계학습에서도 벡터공간에 대한 개념이 나오므로 공부해놓으면 좋겠지요. 가령, 기계학습 공부하다보면 SVM(Support Vector Machine)에서 최대 마진 초평면(MMH, Maximum Margin Hyperplane) 이라고 해서 두 범주를 최대로 나누어주는 평면(Hyperplane)을 찾게 되는데요, 선형대수와 최적화에 대해서 잘 알지 못하면 알고리즘에 대해 깊이 있게 이해하기가 힘듭니다.

 

그럼 순서대로 설명을 해보겠습니다.

  • 벡터공간(vector space)

같은 수의 성분을 가지는 벡터들로 이루어진 공집합이 아닌 집합 V가 있을 때,

- V에 속하는 임의의 두 벡터 ab의 일차결합이 αa + βb (α, β 는 임의의 실수)가 또한 V에 속하고

- 벡터에 대한 덧셈과 스칼라곱이 아래의 8가지 벡터의 합과 스칼라곱에 대한 연산법칙을 만족하면 집합 V를 벡터공간(vector space) 또는 선형공간(linear space)이라고 하며, 그 원소를 벡터(vector)라고 합니다.

 

 벡터의 합에 대해

   (1) abba   : 교환(commutative)법칙

   (2) (a + b) + ca + (b + c)   : 결합(associative) 법칙

   (3) a + 0 = a : 항등원

   (4) a + (-a) = 0 : 역원

 

  스칼라곱에 대해

   (5) c(a + b) = ca + cb : 분배법칙

   (6) (c + k)a = ca + ka : 분배법칙

   (7) c(ka) = (ck)a

   (8) 1a = a 

 

 

"벡터는 좌표축과 무관한 개념입니다. 벡터의 "방향"을 놓고 보면, 이 우주에서 유일한 절대 좌표가 존재하지 않는 한 방향이 무엇인지 정의하기가 쉽지 않습니다. 반면에, 두 벡터의 방향이 같다는 것은 한 벡터의 길이를 적당히 늘여 다른 벡터와 일치하게 만들 수 있는 것으로 간단히 정의할 수 있습니다. 이런 점에서 벡터를 실수배하는 것은 벡터의 크기와 방향을 추상화하는데 있어 중요한 개념입니다. 벡터를 추상화하는데 있어 (1) 두 벡터의 합, (2) 벡터의 실수배, 이 두가지 연산이 가장 중요합니다."

(출처 : "8일간의 선형대수학", 박부성 지음, 경문사)

 

이게 왜 중요한지, 무슨 의미가 있는지 의아하실 수도 있는데요, 아래 벡터와 벡터공간에 대한 역사에 대한 인용글을 한번 보시지요.

 

수학에서 방향과 크기를 가진 양으로서 벡터를 다루게 된 것은 복소수에 대한 연구에서 비롯되었다. 복소수를 2차원 공간의 한 점으로 생각할 수 있다는 아이디어는 노르웨이의 베셀(Wessel)에서 비롯되어, 가우스를 비롯한 수많은 수학자들에 의해 크게 발전하였다. 이후 복소수를 확장하여, 3차원 공간의 한 점을 나타내는 새로운 수체계인 사원수(quaternion)를 구성하는 데 성공한 수학자는 아일랜드이 해밀턴(Hamilton) 이었다. 이후 그라스만(Grassmann), 페아노(Peano) 등에 의해 추상적인 벡터공간(vector space)의 개념이 도입되었다.

... 중략 ...

이것은 벡터를 구체적으로 정의한 다음 그 모임으로 벡터공간을 정의하는 보통의 관점을 뒤집은 것이다. 어떤 대상을 직접 정의하는 대신, 그 대상에 대해 성립해야 하는 연산을 통하여 거꾸로 대상을 정의하는 것은 혁명적인 관점 전환이라 할 수 있다. 한편 이 정의는 벡터의 크기를 정의하지 않는다는 점에서 "크기와 방향을 가진 양"이라는 고전적 의미의 벡터를 더 추상화한 것으로 생각할 수 있다

 

    - 출처 : "8일간의 선형대수학", 박부성 지음, 경문사

 

선형대수학이 이해하기 어려운 이유 중의 하나가 '추상화'된 정도가 심한 학문이기 때문일텐데요, 그게 수학의 역사에서는 혁명적인 관점의 전환이라고도 하는군요. 

 

 

  • 벡터 부분공간(vector subspace)

 벡터공간 V의 공집합이 아닌 부분집합 W가 벡터공간 구조를 가질 때, 즉 부분집합 W가 벡터공간 V에서 정의된 (1) 덧셈 연산과 (2) 스칼라곱 연산을 만족할 때, 그 부분집합 W를 벡터 부분공간(vector subspace)이라고 합니다.

 

좀 어렵지요? ^^' 한번더 풀어서 설명하자면 이렇습니다.

 

 

 

위에서 벡터공간(vector space) V의 부분집합 W가 위에서 설명한 (1) 덧셈 조건, (2) 스칼라배 조건을 모두 만족할 때 W를 부분공간(subspace)라고 했는데요, 이를 벤 다이어그램(venn diagram)으로 나타내보면 아래와 같습니다.

 

 

 

 

부분공간은 '원점을 지나는 직선'이나 '원점을 지나는 평면'(zero vector를 포함)인데요, 좀더 쉽게 설명하기 위해서 부분공간인 경우의 예를 들어보겠습니다. 아래 예는 '원점을 지나는 평면'인 부분공간 예가 되겠습니다.

 

 

 

 

좀더 확실한 이해를 돕기 위해 부분공간이 아닌 경우를 아래에 예로 들어보겠습니다.  부분공간의 2가지 조건이었던 (1) 덧셈 조건, (2) 스칼라곱 조건을 만족하지 않으면 부분공간이라고 할 수 없겠지요?  아래 예를 참고하시기 바랍니다.

 

 

 

 

  • 생성공간(span), 생성된 부분공간(space spanned by)

 성분의 수가 같은 벡터들 a(1), ..., a(n)이 주어졌다고 하고, 이들의 1차결합으로 표현되는 모든 벡터들의 집합을 이들 벡터들의 생성된 부분공간(space spanned by)이라고 합니다. 생성공간(span)은 그 자체로 벡터공간이 되며, 만일 주어진 벡터들 a(1), ..., a(n)이 1차독립이라면, 이 벡터들은 해당 생성공간의 기저가 됩니다.

 

무슨 말이가 어렵죠? ^^'

 

위의 a(1), ..., a(n) 벡터를 풀어서 설명해보면 아래와 같습니다.

 

 

 

 

이걸 예를 들어서 한번 더 풀어보겠습니다.  아래의 x1x2 평면(plane)은 vector(3, 0, 0)과 vector(0, 2, 0) 에 의해 생성된 R^3의 부분공간 (space spanned by (3,0,0), (0,2,0)) 이 되겠습니다. 당연히 아래 생성공간은 벡터공간이며, vector(3,0,0)과 vector(0,2,0)은 선형독립(1차 독립)이므로 이 두 벡터의 집합은 벡터공간의 기저(base)가 되겠습니다.

 

 

위의 예의 생성된 공간(span)은 기저의 원소(벡터)의 개수가 2개이므로 2차원(2 dimension)의 부분공간(subspace)이 된답니다.  차원의 개념은 아래 설명을 참고하세요.

 

 

 

  • 차원(dimension)

벡터공간 V에 속한 1차독립 벡터들의 최대수를 V의 차원(dimension)이라 부르고, dim V로 표기합니다. 여기서 벡터공간의 차원은 유한(finite)하다고 가정합니다.

 

W가 R^m의 부분공간이고, 벡터 a(1), a(2), ..., a(n) 이 W의 선형독립 원소라고 할 때, 기저의 원소이 개수를 부분공간 W의 차원이라고 합니다.  이를 좀더 쉽게 풀어서 쓰면 아래와 같습니다.

 

 

 

앞으로 선형사상을 공부하게 되면 n 차원의 상에 m*n 행렬을 곱해서 m차원의 상으로 바꾸는게 나옵니다. 예를 들면, 2차원 영화를 3차원 3D영화로 바꾼다거나, 3차원 3D영화를 2차원 2D영화로 영상을 바꿀 때 선형대수가 쓰인답니다. 물리학자들이 말하는 초끈이론에서는 11차원속에서 진동하는 미세한 에너지끈을 연구를 한다는것을 들어보신분도 있을텐데요, 3차원까지는 우리가 상상을 해도 4차원 이상이 되면 '도대체 4차원, 5차원, 6차원....11차원이 뭐지?'라고 갸우뚱할 분이 많을 것 같습니다. 

 

이세돌과 대국을 펼쳤던 알파고는 "19 x 19 바둑판의 각 칸마다 48차원의 특징점들을 적용하여 총 19x19x48=17328차원의 거대한 벡터를 입력값으로 사용하였는데, 이는 마치 이미지와 같은 고차원의 상태공간으로 볼 수 있다"(핸드폰 메모장에 적어놨던건데요, 출처 기억 못함... -_-;)고 하는군요. 

 

암튼 수학자들이 정의하는 차원은 위와 같습니다. m차원의 R^m 벡터공간의 부분집합 W의 원소가 n개 이면 W의 차원은 n차원이 된다. 헷갈리고 이해가 안된다면 위의 설명 한번 더 보시구요. ^^'

 

 

R 의 matrix() 함수를 사용해서 m*n 행렬(matrix)를 만드는 방법과, dim() 함수를 사용해서 차원(dimension)을 알아보는 방법은 아래와 같습니다.

 

 
> A <- matrix( 
+      c(1:12), # the data elements 
+      nrow=3,              # number of rows 
+      ncol=4,              # number of columns 
+      byrow = TRUE)        # fill matrix by rows
> A
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    5    6    7    8
[3,]    9   10   11   12
> 
> dim(A)
[1] 3 4

 

 

 

다음 포스팅에서는 선형사상에 대해 알아보고, 그 다음으로 핵(kernel, Ker f), 상공간(Image, Im f), 차원정리(dimension theorem), 계수(rank)에 대해서 차례로 알아보겠습니다.

 

이번 포스팅이 도움이 되었다면 아래의 공감 ♡ 꾸욱~ 눌러주세요. ^^

 

 

728x90
반응형
Posted by Rfriend
,

2016.4월10일, 오후 7시56분 작성

 

Kpop 스타5 우승 이수정준우승 안예은 확정 됐네요.

 

3~4위는 이시은, 마진가S,

 

5~6위는 유제이, 우예린,

 

7~8위는 박민지, 정진우,

 

9~10위는 주미연, 소피한,

 

이렇게 Kpop 스타5의 대 여정이 끝났습니다.

Kpop 스타5 결과 조회하려 블로그 들어오는 분이 있을까봐 예전에 써놨던 글에 덧붙여서 결과 올려요.

 

안테나의, 안테나에 의한, 안테나를 위한 Kpop 스타5 였던듯...

유희열의 안목과 사람을 끄는 매력에 경의를 표합니다.

 

저는 이시은씨랑 유제이씨 응원했는데요, 결승 못가서 쫌매 아쉬웠어요.

저희 온가족이 즐겼던 Kpop 스타5, 참 즐거웠어요. ^^

 

==================================================

 

2016.3월6일, 오후5시46분 작성

 

TV를 거의 안보는 우리집에서 온가족이 다같이 보는 프로그램 Kpop스타5의 Top10이 지지난주에 결정이 되었습니다. 

 

그리고 지난주에는 Top10 B조 5명의 예선이 있었습니다. 결과는 미스터 미스터리 자작곡을 부른 안예은이 1등, 박민지가 2등, 마진가S가 3등을 했지요. 그리고 주미연과 이시은은 탈락후보였습니다.

 

이글을 쓰는 시간이 2016년 3월6일 오후 5시30분이니, 앞으로 딱 1시간 후면 Top10 A조 예선이 치뤄지겠네요.

 

 

[ Kpop스타5 Top10 ]

 

* 사진출처 : SBS홈페이지, Kpop스타5

 

 

 

 

 

재미로 아들이랑 누가 Kpop스타5 Top10 A조 예선에서 1~3등을 할지 맞추는 내기를 해보았습니다. 

 

아들은 그동안 Kpop스타를 보면서 쌓은 나름의 심사 노하우(?)를 가지고 평가표를 만들어서 점수를 매기는 식으로 1~3등을 선정했습니다.  음정, 박자, 호흡, 색깔, 희귀성, 가창력, 감정, 몸(목)관리, 힘, 끼, 자신감, 열정, 덜 떰, 팀웍(팀만), 선곡, 대중성의 기준별로 가중치를 달리해서 점수를 주고 합산하는 식으로요.  이거 제가 소비자행동론이랑 광고론 수업 시간에 많이 봐왔던 평가모델인데... 아들이 이런 평가표를 만들다니 은근 기특하더군요. ㅋㅋ

 

아들의 예상 점수표에 의하면 1등 이수정, 2등 우예린, 3등 유제이 네요.  정진우와 소피한은 탈락후보로 점수를 매겼습니다.

 

[ 아들의 Top10 A조 예선 등수 점수표 ]

 

 

 

 

저는 네이버트렌드에서 2015.11월~2016.3월 현재까지의 Top10 A조 멤버들의 검색 트렌드를 가지고 순위를 예측해보았습니다.  검색이 많이 되었을 수록, 검색 추세가 상승 추세일 수록, 이전보다 최근에 더 높을 수록 1~3등에 들 가능성이 높다고 가정하였습니다.

 

제가 네이버트렌드로 분석해본 결과에 의하면 Top10 A조의 1~3등 예상 순위는, 1등 유제이, 2등 이수정, 3등 우예린입니다.  정진우와 소피한은 탈락후보이구요.

 

 

[ 네이버트렌드의 Top10 A 조 5명의 최근 3개월 검색 트렌드 ]

 

* 출처 : 네이버트렌드 (http://datalab.naver.com/)

 

 

* 출처 : 네이버트렌드 (http://datalab.naver.com/)

 

 

 

우연의 일치인지는 몰라도 아들과 저의 탈락후보가 같네요. 1~3등은 순서가 조금 다르구요.  아들은 우예린을 2등으로 예상했어요.  지난주에 안예은이 미스터 미스터리로 멋지게 1등을 하면서 아무도 예상못했던 대반란을 일으켰던걸 생각하면, 아들의 예상이 저보다 더 들어맞을지도 모르겠습니다.

 

자, 과연 누가 1~3등을 하고 누가 탈락후보가 될지 이제 45분 후면 확인할 수 있겠네요.

두둥~

 

ps. 이거 재미로 쓴 글이예요. 아들이랑 내기(더 많이 맞춘 사람한테 2천원 주기...ㅋㅋ)하다가 블로그에 써봐도 재미있겠다 싶어서요.  너무 심각하게 받아들이지 마시길요... ^^'

 

2016.3월6일, 오후5시46분 올림.

 

 

728x90
반응형
Posted by Rfriend
,

"성경대로 비즈니스하기"라는 부제목을 가지고 있는 'P31' 이라는 책을 소개하고 싶습니다.

 

책 제목 P31 은 성경의 잠언 31장, "Proverbes 31" 에서 따온 것이예요. 지혜의 왕 솔로몬의 그 잠언서입니다. 크리스천 중에는 하루에 성경을 한장씩 읽는 분들도 많은데요, 특히 잠언이 모두 31장으로 되어있고 지혜가 충만한 내용이다보니 한달 기간 동안 하루에 1장씩 읽기에 좋아서 많이 읽는 편이랍니다. P31은 잠언의 마지막 31번째 장의 내용이예요.

 

저자에 대해서 간략히 소개하자면, 하형록 저자는 미국 주차빌딩 건축 설계의 1등 업체인 팀하스(TimHaahs)의 회장이자 오바마 정부 건축자문위원입니다. 그는 목회자 부모님과 함께 초등6학년까지는 부산 한센병 환자촌에서 지내다가 선교사의 도움으로 온가족이 미국에 건너가게 됩니다. 나이 스물아홉 젊은 나이에 회사 중역에 오를만큼 성공가도를 달리던 그에게 심실빈맥이라는 병이 찾아옵니다. 서른 세살의 나이에 죽음의 문턱을 넘나들며 하루 하루가 위태로운 삶을 살게 됩니다. 이때 하형록 회장은 성경 말씀 속에서 하나님을 만나게 되고 하나님의 사람으로 거듭나게 되었다고 고백하고 있습니다. 하형록 회장은 두번의 심장이식 수술을 마치고 난 후에 잠언 31장(P31)에서 얻은 지혜로 "성경대로 비즈니스를 해보겠다"는 사명으로 팀하스(TimHaahs)를 창업하게 되었습니다.

 

 

 

 

'만약 하형록 회장이 죽음의 고비를 맞이하지 않고 아메리칸드림을 이루며 성공대로만을 탄탄히 달렸다면 하나님께 매달리고 하나님을 만날 수 있었을까' 하는 생각을 해보았습니다. 성경에도 보면 "심령이 가난한 자는 복이 있나니 천국이 저희 것임이요(마 5:3)" 라는 말씀이 있거든요.

 

저자 소개가 좀 길었는데요, 이 책을 읽어보면 저자는 '선데이 크리스천'으로서 '주일 교회에서 따로, 평일 회사에서 따로'인 사람이 아니라 정말로 '성경대로 비즈니스를 하고' 있다는 것을 알 수 있습니다. 성경말씀에서 과연 무슨 '비즈니스의 지혜'를 얻을 수 있을까 하고 의아할 수도 있겠습니다.

 

하형록 회장이 말하는 잠언 31(P31)에서 얻은 비즈니스 지혜를 몇가지 소개하고자 합니다.

 

잠언31장20절 말씀, "그는 곤고한 자에게 손을 펴며 궁핍한 자를 위하여 손을 내밀며 (She opens her arms to the poor and extends her hands to the needy)"을 보고 저자는 심장수술을 받고 돌아와 팀하스(TimHaahs) 회사를 창업할 생각을 하며, 회사의 사명으로 "우리는 어려운 이들을 위해 존재한다 (We exist to help those in need)"을 정하였습니다.

 

회사의 사명, 그거 그냥 액자에 멋지게 글자써서 벽에 걸어놓고 '사명 따로, 회사의 운영체계 따로'인 경우가 참 많습니다.  게다가 '00업계 1등 회사', '초일류 회사' 등과 같이 경쟁지향적이고 성장지향적인 사명과는 판이하게도 "우리는 어려운 이들을 위해 존재한다"라는 사명이라니요. 심지어 2번에 걸친 심장이식 수술과 장기입원치료, 약값등...전 재산을 날리고 쫄딱 망한 상태에서 회사를 창업하는 마당에 내건 사명이었습니다.

 

책을 읽다보면 팀하스 회사가 사람을 뽑을 때 회사의 사명에 대해서 오랜 시간을 들여서 설명을 해주고, 또 입사지원을 한 사람이 회사의 사명, 조직문화와 잘 맞을 것인지에 대해서도 역시 오랜 시간과 정성을 들여 알아보고 서로 확인하는 절차를 가지고 있음을 알 수 있습니다.  이 회사의 사명에 끌리어 입사지원을 하는 사람도 있다고 하구요.

 

"보통 31장 10절부터 시작하는데 30분 이상이 걸리는 설교나 다름없다. 우리는 20년 동안 100여 명의 직원을 뽑기 위해 천 명 이상을 상대로 이런 인터뷰를 해 왔다. 보통 한 사람을 인터뷰하는 데 2~3시간이 걸리다 보니 인사 담당 직원들이 여간 고생하는 게 아니다. 그렇게 직원을 뽑고 나면 훨씬 더 긴 시간에 걸쳐 오리엔테이션을 갖는다. 잠언 31장을 보다 더 자세히 설명하는 것이다.

 그런 방법으로 직원을 뽑고 함께 일을 하다 보면 확실히 사람들이 달라진다. 그들도 인터뷰에서부터 이 회사가 보통 회사와는 다르다는 것을 느끼고 이전 회사에서는 시도해 본 적 없던 일을 하나씩 해 보려고 노력하게 된다" 

 - P31, 62page

 

 

아래에 하형록 회장이 회사에 적용하는 잠언 말씀들을 소개해보겠습니다.

 

잠언31장 10절, "누가 현숙한 여인을 찾아 얻겠느냐. 그의 값은 진주보다 더하니라 (A wife of noble character who can find? She is worth far more than rubis)"

=> 고귀한 성품을 가진 회사 (Be rare)

 

잠언31장 11절, "그런 자의 남편의 마음은 그를 믿나니 산업이 핍절하지 아니하겠으며 (Her husband has full confidence in her and lacks nothing of value)"

=> 고객의 신뢰를 얻는 회사 (Earn trust)

 

잠언31장 12절, "그런 자는 살아 있는 동안에 그의 남편에게 선을 행하고 악을 해하지 아니하느니라 (She brings him good, not harm, all the days of her life)"

=> 상처를 주지 않는 회사 (Be kind)

 

잠언31장15절, "밤이 새기 전에 일어나서 자기 집안사람들에게 음식을 나누어 주며 여종들에게 일을 정하여 맡기며 (She gets up while it is still dark; she provides food for her family and portions for her servant girls)"

=> 인정을 베푸는 회사 (Provide)

 

잠언31장 16절, "밭을 살펴보고 사며 자기의 손으로 번 것을 가지고 포도원을 일구며 (She considers a field and buys it; out of her earnings she plants a vineyard)"

=> 신중하게 투자하는 회사 (Invest prudently)

 

잠언31장 17절, "힘 있게 허리를 묶으며 자기의 팔을 강하게 하며 (She sets about her work vigorously; her arms are strong for her tasks)"

=> 다 함께 뛰는 회사 (Work diligently)

 

잠언31장 18절, "자기의 장사가 잘되는 줄을 깨닫고 밤에 등불을 끄지 아니하며 (She sees that her trading is profitable, and her lamp does not go out at night)"

=> 이윤을 창출하는 회사 (Make profit)

 

잠언31장 19절, "손으로 솜뭉치를 들고 손가락으로 가락을 잡으며 (In her hand she holds the distaff and grasps the spindle with her fingers)"

=> 주인이 솔선수범하는 회사

 

잠언31장 20절, "그는 곤고한 자에게 손을 펴며 궁핍한 자를 위하여 손을 내밀며 (She opens her arms to the poor and extends her hands to the needy)"

=> 높은 목적을 가진 회사

 

잠언31장 21절, "자기 집 사람들은 다 홍색 옷을 입었으므로 눈이 와도 그는 자기 집 사람들을 위하여 염려하지 안니하며 (When it snows, she had no fear for her household; for all of them are clothed in scarlet)"

=> 항상 준비된 회사 (Prepare for uncertainty)

 

잠언31장 22절, "그는 자기를 위하여 아름다운 이블을 지으며 세마포와 자색 옷을 입으며 (She makes coverings for her bed; she is clothed in fine linen and purple)"

=> 단정한 차림의 회사 (Dress well)

 

잠언31장 23절, "그의 남편은 그 땅의 장로들과 함께 성문에 앉으며 사람들의 인정을 받으며 (Her husband is respected at the city gate, where he takes his seat among the elders of the land)"

=> 고객의 성공을 돕는 회사 (Help the client get promoted)

 

잠언31장 24절, "그는 베로 옷을 지어 팔며, 띠를 만들어 상인들에게 맡기며 (She makes linen garments and sells them, and supplies the merchants with sashes)"

=> 엑스트라 마일을 실천하는 회사 (Go the extra mile)

 

잠언31장 25절, "능력과 존귀로 옷을 삼고 후일을 웃으며 (She is clothed with strength and dignity; she can laugh at the days to come)"

=> 품격과 인품을 갖춘 회사 (Be gistinguished)

 

잠언31장 26절, "입을 열어 지혜를 베풀며, 그의 혀로 인애의 법을 말하며 (She speaks with wisdom, and faithful instruction is on her tougue)"

=> 인애로 격려하고 조언하는 회사 (Be eloquent)

 

잠언31장 27절, "자기의 집안일을 보살피고 게을리 얻은 양식을 먹지 아니하나니 (She watches over the affairs of her household and does not eat the bread of idleness)"

=> 투명한 회사 (Be honest)

 

잠언31장 28~29절, "그의 자식들은 일어나 감사하며, 그의 남편은 칭찬하기를 덕행 있는 여자가 많으나, 그대는 모든 여자보다 뛰어나다 하느니라 (Her children arise and call her blessed; her husband also, and he praises her: "Many women do noble things, but you surpass them all.")

=> 가족의 칭찬과 인정을 받는 회사 (Praise that matters)

 

잠언31장 30절, "고운 것도 거짓되고 아름다운 것도 헛되나, 오직 여호화를 경외하는 여자는 칭찬을 받을 것이라 (Charm is deceptive, and beauty is fleeting; but a women who fears the LORD is to be praised.)

=> 하나님을 두려워하는 회사 (The true wisdom)

 

잠언31장 31절, "그 손의 열매가 그에게로 돌아갈 것이요, 그 행한 일로 말미암아 성문에서 칭찬을 받으리라 (Give her the reward she has earned, and let her works bring her praise at the city gate)"

=> 하나님의 언약을 체험하는 회사 (The reward, the promise)

 

이렇게 잠언 말씀과 회사에 적용하는 키워드만 적어놓으니 좀 밋밋해보이고 잘 안와닿을 수도 있겠습니다. 그리고 내용도 길어졌네요. ^^; 책에는 이들 소제목별로 저자가 직접 회사에서 실제 적용해보고 그 가치를 실증해보인 무수한 사례가 소개되어 있습니다. 세상 사람들은 21세기에 성경 말씀대로 비즈니스를 한다고 하면 비웃을지 몰라도, 저자는 말로만 설교를 한 것이 아니라, 실제로 잠언31장 말씀에 기초해서 회사를 새우고 말씀대로 행했던 간증을 하고 있는 것입니다. 책을 사서 회사에서 저자가 적용했던 성공과 실패의 사례들을 읽다보면 위의 성경말씀들이 현 시대에도 통하는 말씀이구나 하고 납득이 되실거라고 믿습니다. 책 일독을 권합니다.

 

그럼, 이런 의문이 들 것입니다. '성경대로 비즈니스를 하면 회사 실적이 좋을까? 과연 성공할 수 있을까?' 책의 서문에 나오는 회사 소개내용을 보면 "올해로 20주년을 맞이한 '팀하스'는 미국 젊은이들이 가장 일하고 싶어하는 회사 중 하나"라고 하네요.

 

 

크리스천 중에 '교회에서 따로, 회사에서 따로'인 이중적인 삶에 고민이신 분은 이 책을 읽어보시면 좋겠습니다.  크리스천 아닌 분이 이 책을 읽고 하나님께로 나아오는 계기가 된다면 더더욱 좋겠구요.

 

애덤그랜트의 '기브 앤 테이크 (Give and Take)'라는 책에서 저자가 주장했던 "성공하려면 베푸는 삶을 살아라"는 내용과도 일맥상통하는 데가 있습니다. 크리스천이 다른 점이 있다면 "하나님은 구원을 선물로 주시지만 구원받은 사람은 그 선물을 이웃에게 나누어야 한다(63page)"는 점이라고 할까요. 성공하기 위해 베푸는 것이 아니라, 하나님께서 사랑을 먼저 보여주셨기 때문에 우리도 (조건없이) 남에게 사랑을 전하는 것이고, 성공은 후에 덤으로 따라오는 것이라는 것이지요.

 

비전과 사명, 기업/조직문화, 섬기는 리더십(Servant leadership), 인력 채용/육성/보상 등의 체계, 기업의 사회적 책임 등에 대해서 연구하는 분이라면 P31 에 기초해서 새워지고 전 조직 구성원이 공통이 사명 하에 일하고 있는 '팀하스(TimHaash)' 회사를 대상으로 연구를 해보면 좋을 것 같습니다.  이전에 소개했던 다니엘핑크의 '드라이브(Drive)' 책에 나오는 제3의 드라이브로 움직이는 회사의 적절한 예로 '팀하스(TimHaash)'를 들 수 있겠다 싶어요.

 

 

 

멋진 말과 글로 책을 잘 쓰는게 쉽지 않은 일이긴 합니다만, 말과 글대로 산다는 것, 말과 행동이 일치한다는 것은 더 어려운 일이겠지요.  특히나 외부인에게는 소위 말해 체면과 염치도 따져야 하니 조신하게 행동할 수 있어도, 가장 가까운 가족에게는 남에게 보이는 모습과는 다른 본성(?)을 숨기기 힘들다고 생각합니다.  그런면에서 봤을 때 하형록 회장의 따님 두분이 책 서두에 써놓은 추천사가 정말 인상에 깊게 남았습니다.  저도 아들과 딸을 둔 아버지인지라 더욱 그랬던거 같습니다. 두 딸들은 무어라 말했을지 궁금하시죠?

 

 

"아버지는 가정, 교회, 사업이 전체적으로 맞물려 움직일 때에만 우리 삶이 완전해진다고 믿는 분이다 그분의 딸로서 살면서 아버지의 이런 가치가 삶에서 나타나는 것을 보았고, 그로 인해 아버지의 발길이 닿는 곳마다 삶이 변화되는 것을 보았다."

  - 크라스타나 하스 (하형록 회장의 큰딸)

 

 

"아버지는 당신이 가르친 대로 사는 분이다"

  - 줄리아나 하스 (하형록 회장의 작은딸)

 

728x90
반응형
Posted by Rfriend
,

수 3개 이상의 다변량 데이터(multivariate data set)를 2차원 평면에 효과적으로 시각화할 수 있는 방법으로

 

(1) 레이더 차트 (radar chart) or 거미줄 그림(spider plot)

(2) 별 그래프 (star graph) (레이더 차트와 유사, 중심점 차이 존재)

(3) 평행 좌표 그림 (parallel coordinate plot)

(4) 3차원 산점도 (3 dimensional scatter plot)

(5) 체르노프 얼굴그림 (Chernoff faces)

(6) 산점도 행렬(scatter plot matrix)

(7) 모자이크 그림(mosaic plot)

 

등이 있습니다. 

 

이번 포스팅에서는 (5) 체르노프 얼굴그림 (Chernoff faces)에 대해서 소개하겠습니다. 

 

체르노프 얼굴그림은 다변량 변수의 속성값들을 아래의 표에 나오는 것처럼 15가지의 얼굴의 생김새(얼굴 높이, 얼굴 넓이, 입 높이, 입 넓이...등) 특성에 매핑해서 얼굴 모양이 달라지게 하는 방식입니다.

 

 얼굴 특성 (face characteristics)

다변량 변수 (multivariate mapping)

 1. 얼굴의 높이

 "height of face   "    "Price"

 2. 얼굴의 넓이

 "width of face    "

 "MPG.highway" 

 3. 얼굴의 구조

 "structure of face"

 "Horsepower"

 4. 입의 높이

  "height of mouth  "

 "RPM"       

 5. 입의 넓이

  "width of mouth   "

 "Length"    

 6. 웃음

  "smiling          "

 "Weight"      

 7. 눈의 높이

  "height of eyes   "

 "Price" 

 8. 눈의 넓이

  "width of eyes    "

 "MPG.highway"

 9. 머리카락 높이

  "height of hair   "

 "Horsepower"

 10. 머리카락 넓이

  "width of hair   " 

 "RPM"  

 11. 헤어스타일

  "style of hair   " 

 "Length"      

 12. 코 높이

  "height of nose  " 

 "Weight"    

 13. 코 넓이

  "width of nose   " 

 "Price"     

 14. 귀 넓이

  "width of ear    " 

 "MPG.highway"

 15. 귀 높이

  "height of ear   " 

 "Horsepower"

 

 

체르노프 얼굴그림은 얼굴 모양을 가지고 데이터 관측치들의 특성을 직관적으로 파악할 수 있다는 장점이 있습니다. 다만, 각 변수가 얼굴 모양의 어느 특성에 매핑이 되었는지를 확인하고자 한다면 앞서 살펴본 레이터 차트나 별그림, 평행좌표그림 등에 비해 불편한 편이고, 왠지 official한 느낌은 덜 듭니다. 그래서 저 같은 경우는 회사에서 보고서에 체르노프 얼굴그림을 사용해본 적은 아직까지는 없습니다. ^^;  그래도 다변량 데이터를 신속하게, 직관적으로 탐색적분석 하는 용도로는 알아듬직 하므로 이번 포스팅을 이어가 보겠습니다.

 

 

예제에 사용할 데이터는 MASS Package에 내장되어있는 Cars93 dataframe을 사용하겠으며, 전체 93개의 관측치가 있는데요, 이를 모두 그리자니 너무 많아서요, 1번째 관측치부터 20번째 관측치까지만 사용하겠습니다. 체르노프 얼굴그림 그릴 때 사용할 변수로는 가격("Price"), 고속도로연비("MPG.highway"), 마력("Horsepower"), RPM("RPM"), 차길이("Length"), 차무게("Weight")의 5개만 선별해서 사용하겠습니다. 아래처럼 Cars93_1 이라는 새로운 이름의 데이터프레임을 만들었습니다.

> # dataset preparation
> library(MASS)
> str(Cars93)
'data.frame':	93 obs. of  27 variables:
 $ Manufacturer      : Factor w/ 32 levels "Acura","Audi",..: 1 1 2 2 3 4 4 4 4 5 ...
 $ Model             : Factor w/ 93 levels "100","190E","240",..: 49 56 9 1 6 24 54 74 73 35 ...
 $ Type              : Factor w/ 6 levels "Compact","Large",..: 4 3 1 3 3 3 2 2 3 2 ...
 $ Min.Price         : num  12.9 29.2 25.9 30.8 23.7 14.2 19.9 22.6 26.3 33 ...
 $ Price             : num  15.9 33.9 29.1 37.7 30 15.7 20.8 23.7 26.3 34.7 ...
 $ Max.Price         : num  18.8 38.7 32.3 44.6 36.2 17.3 21.7 24.9 26.3 36.3 ...
 $ MPG.city          : int  25 18 20 19 22 22 19 16 19 16 ...
 $ MPG.highway       : int  31 25 26 26 30 31 28 25 27 25 ...
 $ AirBags           : Factor w/ 3 levels "Driver & Passenger",..: 3 1 2 1 2 2 2 2 2 2 ...
 $ DriveTrain        : Factor w/ 3 levels "4WD","Front",..: 2 2 2 2 3 2 2 3 2 2 ...
 $ Cylinders         : Factor w/ 6 levels "3","4","5","6",..: 2 4 4 4 2 2 4 4 4 5 ...
 $ EngineSize        : num  1.8 3.2 2.8 2.8 3.5 2.2 3.8 5.7 3.8 4.9 ...
 $ Horsepower        : int  140 200 172 172 208 110 170 180 170 200 ...
 $ RPM               : int  6300 5500 5500 5500 5700 5200 4800 4000 4800 4100 ...
 $ Rev.per.mile      : int  2890 2335 2280 2535 2545 2565 1570 1320 1690 1510 ...
 $ Man.trans.avail   : Factor w/ 2 levels "No","Yes": 2 2 2 2 2 1 1 1 1 1 ...
 $ Fuel.tank.capacity: num  13.2 18 16.9 21.1 21.1 16.4 18 23 18.8 18 ...
 $ Passengers        : int  5 5 5 6 4 6 6 6 5 6 ...
 $ Length            : int  177 195 180 193 186 189 200 216 198 206 ...
 $ Wheelbase         : int  102 115 102 106 109 105 111 116 108 114 ...
 $ Width             : int  68 71 67 70 69 69 74 78 73 73 ...
 $ Turn.circle       : int  37 38 37 37 39 41 42 45 41 43 ...
 $ Rear.seat.room    : num  26.5 30 28 31 27 28 30.5 30.5 26.5 35 ...
 $ Luggage.room      : int  11 15 14 17 13 16 17 21 14 18 ...
 $ Weight            : int  2705 3560 3375 3405 3640 2880 3470 4105 3495 3620 ...
 $ Origin            : Factor w/ 2 levels "USA","non-USA": 2 2 2 2 2 1 1 1 1 1 ...
 $ Make              : Factor w/ 93 levels "Acura Integra",..: 1 2 4 3 5 6 7 9 8 10 ...
> 

> # sampling observations from 1st to 20th, selecting 5 variables

> Cars93_1 <- Cars93[c(1:20),c("Price", "MPG.highway", "Horsepower", "RPM", "Length", "Weight")]
> Cars93_1
   Price MPG.highway Horsepower  RPM Length Weight
1   15.9          31        140 6300    177   2705
2   33.9          25        200 5500    195   3560
3   29.1          26        172 5500    180   3375
4   37.7          26        172 5500    193   3405
5   30.0          30        208 5700    186   3640
6   15.7          31        110 5200    189   2880
7   20.8          28        170 4800    200   3470
8   23.7          25        180 4000    216   4105
9   26.3          27        170 4800    198   3495
10  34.7          25        200 4100    206   3620
11  40.1          25        295 6000    204   3935
12  13.4          36        110 5200    182   2490
13  11.4          34        110 5200    184   2785
14  15.1          28        160 4600    193   3240
15  15.9          29        110 5200    198   3195
16  16.3          23        170 4800    178   3715
17  16.6          20        165 4000    194   4025
18  18.8          26        170 4200    214   3910
19  38.0          25        300 5000    179   3380
20  18.4          28        153 5300    203   3515

 

 

 

 

체로노프 얼굴그림을 그리기 위해 R의 aplpack Packagefaces() 함수를 사용하겠습니다.  

install.package() 함수를 써서 설치하고, library() 함수로 호출해 보겠습니다.

 

> install.packages("aplpack")
Installing package into ‘C:/Users/Owner/Documents/R/win-library/3.2’
(as ‘lib’ is unspecified)
trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.2/aplpack_1.3.0.zip'
Content type 'application/zip' length 3156450 bytes (3.0 MB)
downloaded 3.0 MB

package ‘aplpack’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
	C:\Users\Owner\AppData\Local\Temp\Rtmpk3jrgb\downloaded_packages
> 
> library(aplpack)
필요한 패키지를 로딩중입니다: tcltk

 

 

 

 

이제 faces() 함수로 체르노프 얼굴 그림을 그려보겠습니다.

faces(dataset, face.type = 0/1/2, main = "title") 의 형식으로 사용합니다. 

face.type = 0 (line drawing faces)은 색깔 없이 선으로만 얼굴을 그립니다.  

face.type = 1 (the elements of the faces are painted)는 색깔도 같이 칠해서 얼굴을 그려줍니다.

face.type = 2 (Santa Claus faces are drawn)는 산타클로스 얼굴에 색을 칠해서 그려주고요.

아래에 하나씩 예를 들어보겠습니다.

 

  • face.type = 0 (line drawing faces)

> # face.type = 0 : line drawing faces
> faces(Cars93_1, face.type = 0, main = "Chernoff faces: face.type = 0")
effect of variables:
 modified item       Var          
 "height of face   " "Price"      
 "width of face    " "MPG.highway"
 "structure of face" "Horsepower" 
 "height of mouth  " "RPM"        
 "width of mouth   " "Length"     
 "smiling          " "Weight"     
 "height of eyes   " "Price"      
 "width of eyes    " "MPG.highway"
 "height of hair   " "Horsepower" 
 "width of hair   "  "RPM"        
 "style of hair   "  "Length"     
 "height of nose  "  "Weight"     
 "width of nose   "  "Price"      
 "width of ear    "  "MPG.highway"
 "height of ear   "  "Horsepower"

 

 

 

 

 

 

  • face.type = 1 (the elements of the faces are painted)

> # face.type = 1 : the elements of the faces are painted
> faces(Cars93_1, face.type = 1, main = "Chernoff faces: face.type = 1")
effect of variables:
 modified item       Var          
 "height of face   " "Price"      
 "width of face    " "MPG.highway"
 "structure of face" "Horsepower" 
 "height of mouth  " "RPM"        
 "width of mouth   " "Length"     
 "smiling          " "Weight"     
 "height of eyes   " "Price"      
 "width of eyes    " "MPG.highway"
 "height of hair   " "Horsepower" 
 "width of hair   "  "RPM"        
 "style of hair   "  "Length"     
 "height of nose  "  "Weight"     
 "width of nose   "  "Price"      
 "width of ear    "  "MPG.highway"
 "height of ear   "  "Horsepower"

 

 

 

 

  • face.type = 2 (Santa Claus faces are drawn)

> # face.type = 2 : Santa Claus faces are drawn
> faces(Cars93_1, face.type = 2, main = "Chernoff faces: face.type = 2")
effect of variables:
 modified item       Var          
 "height of face   " "Price"      
 "width of face    " "MPG.highway"
 "structure of face" "Horsepower" 
 "height of mouth  " "RPM"        
 "width of mouth   " "Length"     
 "smiling          " "Weight"     
 "height of eyes   " "Price"      
 "width of eyes    " "MPG.highway"
 "height of hair   " "Horsepower" 
 "width of hair   "  "RPM"        
 "style of hair   "  "Length"     
 "height of nose  "  "Weight"     
 "width of nose   "  "Price"      
 "width of ear    "  "MPG.highway"
 "height of ear   "  "Horsepower"

 

 

 

산타클로스 얼굴은 정신이 하도 산만해서 관측치들간의 유사성이나 차이가 눈에 잘 안들어오네요. @@~

 

 

 

  • 체로노프 얼굴그림에 이름 추가하기 : labels =

> # putting labels as face names : labels
> faces(Cars93_1, face.type = 1, labels = Cars93[1:20,]$Model, 
+       main = "putting labels as face names : labels = ")
 
effect of variables: modified item Var "height of face " "Price" "width of face " "MPG.highway" "structure of face" "Horsepower" "height of mouth " "RPM" "width of mouth " "Length" "smiling " "Weight" "height of eyes " "Price" "width of eyes " "MPG.highway" "height of hair " "Horsepower" "width of hair " "RPM" "style of hair " "Length" "height of nose " "Weight" "width of nose " "Price" "width of ear " "MPG.highway" "height of ear " "Horsepower"

 

 

 

 

 

  • 산점도에 체르노프 얼굴그림 겹쳐 그르기 (overlapping chernoff faces over scatter plot)

(1) 먼저 산점도를 plot() 함수를 사용해서 그립니다.

(2) 그 다음에 faces() 함수로 체르노프 얼굴그림을 실행시킵니다. 이때 scale = TRUE, plot = FALSE 옵션을 사용해줍니다. 그래프는 화면에 안나타나구요, (3)번 스텝에서 그래프가 그려질 수 있도록 데이터가 준비된 상태입니다.

(3) plot.faces() 함수를 사용해서 산점도 위에 (2)번에서 생성해 놓은 체르노프 얼굴그림을 겹쳐서 그려줍니다. width 와 height 는 x축과 y축의 단위를 보고서 trial & error 를 해보면서 숫자를 조금씩 바꿔가면서 그려본 후에 가장 마음에 드는 걸로 선택하면 되겠습니다.

 

체르노프 얼굴그림을 산점도에 겹쳐서 그리니 제법 유용한 다차원 그래프이지 않은가요? ^^

 

> # Overlapping Chernoff faces over scatter plot (MPG.highway*Weight)
> plot(Cars93_1[,c("MPG.highway", "Weight")], 
+      bty="n", # To make a plot with no box around the plot area
+      main = "Chernoff faces of Cars93")

 

 

 

 

 

> Cars93_1_faces <- faces(Cars93_1, scale = TRUE, plot=FALSE)
effect of variables:
 modified item       Var          
 "height of face   " "Price"      
 "width of face    " "MPG.highway"
 "structure of face" "Horsepower" 
 "height of mouth  " "RPM"        
 "width of mouth   " "Length"     
 "smiling          " "Weight"     
 "height of eyes   " "Price"      
 "width of eyes    " "MPG.highway"
 "height of hair   " "Horsepower" 
 "width of hair   "  "RPM"        
 "style of hair   "  "Length"     
 "height of nose  "  "Weight"     
 "width of nose   "  "Price"      
 "width of ear    "  "MPG.highway"
 "height of ear   "  "Horsepower" 
> 
> plot.faces(Cars93_1_faces, 
+            Cars93_1[,c("MPG.highway")], 
+            Cars93_1[,c("Weight")], 
+            width = 2, 
+            height = 250)

 

 

 

 

 

체르노프 얼굴그림에 대해서 좀더 알고 싶은 분은 아래의 Reference를 참고하시기 바랍니다.

[ Reference ] http://www.inside-r.org/packages/cran/aplpack/docs/faces

 

많은 도움 되었기를 바랍니다.

 

이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡' 단추를 꾸욱 눌러주세요.^^

 

728x90
반응형
Posted by Rfriend
,

수 3개 이상의 다변량 데이터(multivariate data set)를 2차원 평면에 효과적으로 시각화할 수 있는 방법으로

 

(1) 레이더 차트 (radar chart) or 거미줄 그림(spider plot)

(2) 별 그래프 (star graph) (레이더 차트와 유사, 중심점 차이 존재)

(3) 평행 좌표 그림 (parallel coordinate plot)

(4) 3차원 산점도 (3 dimensional scatter plot)

(5) 체르노프 얼굴그림 (Chernoff faces)

(6) 산점도 행렬(scatter plot matrix)

(7) 모자이크 그림(mosaic plot)

 

등이 있습니다. 

 

이번 포스팅에서는 (4) 3차원 산점도 (3 dimensional scatter plot)에 대해서 소개하겠습니다. 

 

3차원 그래프를 그릴 수 있는 Package가 여러개 있는데요, 그 중에서도 3차원 scatter plot에 특화된 scatterplot3d Package 의 scatterplot3d() 함수를 설명해보겠습니다.

 

예제로 사용할 데이터는 MASS Package에 내장된 Cars93 데이터 프레임의 고속도로연비(MPG.highway), 마력(Horsepower), 무게(Weight) 변수들입니다.

 

> ##----------------------------------------
> ## 3 dimensional scatter plot 
> ##----------------------------------------
> 
> library(MASS)
> str(Cars93)
'data.frame':	93 obs. of  27 variables:
 $ Manufacturer      : Factor w/ 32 levels "Acura","Audi",..: 1 1 2 2 3 4 4 4 4 5 ...
 $ Model             : Factor w/ 93 levels "100","190E","240",..: 49 56 9 1 6 24 54 74 73 35 ...
 $ Type              : Factor w/ 6 levels "Compact","Large",..: 4 3 1 3 3 3 2 2 3 2 ...
 $ Min.Price         : num  12.9 29.2 25.9 30.8 23.7 14.2 19.9 22.6 26.3 33 ...
 $ Price             : num  15.9 33.9 29.1 37.7 30 15.7 20.8 23.7 26.3 34.7 ...
 $ Max.Price         : num  18.8 38.7 32.3 44.6 36.2 17.3 21.7 24.9 26.3 36.3 ...
 $ MPG.city          : int  25 18 20 19 22 22 19 16 19 16 ...
 $ MPG.highway       : int  31 25 26 26 30 31 28 25 27 25 ...
 $ AirBags           : Factor w/ 3 levels "Driver & Passenger",..: 3 1 2 1 2 2 2 2 2 2 ...
 $ DriveTrain        : Factor w/ 3 levels "4WD","Front",..: 2 2 2 2 3 2 2 3 2 2 ...
 $ Cylinders         : Factor w/ 6 levels "3","4","5","6",..: 2 4 4 4 2 2 4 4 4 5 ...
 $ EngineSize        : num  1.8 3.2 2.8 2.8 3.5 2.2 3.8 5.7 3.8 4.9 ...
 $ Horsepower        : int  140 200 172 172 208 110 170 180 170 200 ...
 $ RPM               : int  6300 5500 5500 5500 5700 5200 4800 4000 4800 4100 ...
 $ Rev.per.mile      : int  2890 2335 2280 2535 2545 2565 1570 1320 1690 1510 ...
 $ Man.trans.avail   : Factor w/ 2 levels "No","Yes": 2 2 2 2 2 1 1 1 1 1 ...
 $ Fuel.tank.capacity: num  13.2 18 16.9 21.1 21.1 16.4 18 23 18.8 18 ...
 $ Passengers        : int  5 5 5 6 4 6 6 6 5 6 ...
 $ Length            : int  177 195 180 193 186 189 200 216 198 206 ...
 $ Wheelbase         : int  102 115 102 106 109 105 111 116 108 114 ...
 $ Width             : int  68 71 67 70 69 69 74 78 73 73 ...
 $ Turn.circle       : int  37 38 37 37 39 41 42 45 41 43 ...
 $ Rear.seat.room    : num  26.5 30 28 31 27 28 30.5 30.5 26.5 35 ...
 $ Luggage.room      : int  11 15 14 17 13 16 17 21 14 18 ...
 $ Weight            : int  2705 3560 3375 3405 3640 2880 3470 4105 3495 3620 ...
 $ Origin            : Factor w/ 2 levels "USA","non-USA": 2 2 2 2 2 1 1 1 1 1 ...
 $ Make              : Factor w/ 93 levels "Acura Integra",..: 1 2 4 3 5 6 7 9 8 10 ...

 

 

 

 

library(scatterplot3d)로 패키지를 로딩합니다.

 

scatterplot3d(x, y, z, ...)로 3차원 그래프의 x, y, z 좌표(coordinate)를 지정해줍니다. 아래 예제에서는 x축에 무게(Weight), y축에는 마력(Horsepower), z축에는 연비(MPG.highway)를 할당하였습니다.

 

type = "h" 는 수직선으로 표현하라는 옵션입니다. "p"는 점으로 표현, "l"은 선으로 표현하라는 의미입니다. 아래 예시의 경우는 3차원 공간에 나타내다 보니 "p"나 "l"보다는 "h"가 점과 x, y축 기준 수직선이 함께 보여서 인지하기에 더 수월하기에 type = "h"로 해서 그려보았습니다.

 

scale.y = 0.7 은 x축과 z축을 기준으로 상대적으로 y축은 0.7 배로 해서 나타내라는 뜻입니다. 아래의 프로그램을 복사한 다음에 숫자를 바꿔서 한번 그려보시면 그래프가 어떻게 바뀌는지 금방 이해하실 겁니다.

 

angle = 50 은 x와 y축의 각도를 뜻합니다.  scale.y 와 angle 옵션의 숫자를 바꿔가면서 분석가가 원하는 길이, 각도가 나올 때까지 몇 번 trial and error 로 시도를 해보시면 됩니다.

 

highlight.3d = TRUE  옵션은 y축의 좌표를 기준으로 색깔이 달라지게 하라는 의미입니다. 아래 그래프의 경우 y축 좌표 값이 작을 수록 빨간색, y축 좌표값이 클수록 검정색으로 자동으로 바뀌었습니다.  만약 highlight.ed = FALSE 라고 지정하면 그냥 y축 좌표값이 어떻게 되던간에 모두 검정색으로 나오게 되므로 3차원의 공간감을 나타내는데 부족함이 있습니다. 따라서 highlight.3d = TRUE 옵션 사용을 권장합니다.

 

box = TRUE  옵션은 아래에 파란색(col.axis = "blue")으로 표시된 부분을 그리라는 뜻입니다. default 는 box = TRUE 이므로 별도로 명기하지 않아도 되며, 표기하기 싫을 때는 box = FALSE 라고 표기해야 겠지요.

 

grid = TRUE 는 아래의 예에서 회색(col.grid = "gray")으로 표시된 부분을 나타낼지 정하는 옵션입니다. 이 역시 default 는 grid = TRUE 이므로 별도로 명기하지 않아도 되며, grid 를 제외하고 싶은 때는 grid = FALSE 라고 옵션을 부여하면 됩니다.

 

mar = c(3, 4, 4, 3) 은 아래쪽, 왼쪽, 위쪽, 오른쪽의 순서대로 margin을 부여하는 옵션입니다.  margin도 숫자를 조금씩 바꿔가면서 한번 시험해보시기 바랍니다.  그래프가 margin에 따라서 조금씩 바뀌는걸 알 수 있을 겁니다.  귀찮으면 그냥 default margin c(5.1, 4.1, 4.1, 2.1) 을 사용하면 되겠습니다(mar 옵션 미사용하면 default margin 적용됨).

 

xlab, ylab, zlab 은 x축, y축, z축에 label 부여할 때 사용하는 옵션입니다.

 

main = "xxx"은 제목 붙이는 옵션이구요.

 

 

> library(scatterplot3d) > > x <- Cars93$Weight > y <- Cars93$Horsepower > z <- Cars93$MPG.highway > > > # 3 dimensional scatter plotting > Cars93_3d <- scatterplot3d(x, y, z, + type = "h", # "p" for point, "l" for line, "h" for vertical lines to x-y-plane + pch=16, # symbol, character + scale.y = 0.7, # scale of y axis related to x- and z axis + angle = 50, # angle between x and y axis + highlight.3d=TRUE, # points will be drawn in different colors related to y coordinates + box = TRUE, # a logical value indicating whether a box should be drawn around the plot + col.axis="blue", # the color to be used for axis + grid = TRUE, # a logical value indicating whether a grid should be drawn on the plot + col.grid="gray", # the color to be used for grid + mar = c(3, 4, 4, 3), # margin : c(bottom, left, top, right) + xlab = "x_Weight", # label for the x + ylab = "y_Horsepower", # label for the y + zlab = "z_MPG.highway", # label for the z + main="3 dimensional scatter plot of Cars93") # main title

 

 

 

 

 

 

혹시 색깔을 좀더 다양하게 해보고 싶다면 아래처럼 color 옵션을 사용하면 됩니다. rainbow color를 적용해보았습니다. 저는 위에서 그린 highlight.3d = TRUE 옵션이 아래의 color = rainbowcolor 로 화려하게 그린 그래프보다 시각적으로 더 인지하기에 좋아 보이네요.  아래 그림은 좀 어지럽게 느껴지구요.

 

> # using rainbow color

> dim(Cars93)
[1] 93 27

> rainbowcolor <- rainbow(93) # number 93 indicate 93 observations of Cars93 dataframe > > Cars93_3d <- scatterplot3d(x, y, z, + type = "h", # "p" for point, "l" for line, "h" for vertical lines to x-y-plane + pch=16, # symbol, character + scale.y = 0.7, # scale of y axis related to x- and z axis + angle = 50, # angle between x and y axis + color = rainbowcolor, # colors of points in the plot + box = TRUE, # a logical value indicating whether a box should be drawn around the plot + col.axis="blue", # the color to be used for axis + grid = TRUE, # a logical value indicating whether a grid should be drawn on the plot + col.grid="gray", # the color to be used for grid + mar = c(3, 4, 4, 3), # margin : c(bottom, left, top, right) + xlab = "x_Weight", # label for the x + ylab = "y_Horsepower", # label for the y + zlab = "z_MPG.highway", # label for the z + main="3 dimensional scatter plot of Cars93 - using rainbow color") # main title

 

 

 

 

 

 

다음으로 Cars93_lm <- lm(MPG.highway ~ Weight + Horsepower) 를 사용해서 x축 무게(Weight)와 y축 마력(Horsepower)와 z축 고속도로연비(MPG.highway) 간의 회귀모형을 적합시킨 후에, 3D scatter plot에 회귀평면(regression plane)을 그려보도록 하겠습니다.  보통 2차원 산포도를 그리고 선형회귀모형을 적합시킨 후에 선형회귀선을 2차원 산포도에 추가로 그려놓고는 했었을 것입니다. 아래 예시는 z ~ x + y 로 회귀모형을 적합시켜서 3차원 그래프로 그린 것인데요, 아무래도 2차원 그래프보다는 좀 이해하기가 어렵습니다. 

 

> # Adding a regression plane to the "scatterplot3d"
> attach(Cars93)

> Cars93_lm <- lm(MPG.highway ~ Weight + Horsepower) > Cars93_3d$plane3d(Cars93_lm, lty.box = "solid")

> detach(Cars93)

 

 

 

 

 

 

 

만약 위의 그래프를 톰크루즈가 주연으로 나왔던 영화 minority report 처럼 3차원 그래프를 상, 하, 좌, 우로 자유자재로 돌려볼 수 있다면 아마도 좀더 데이터의 분포 형태를 좀더 인지하기가 쉬울 것입니다.  아쉽게도 scatterplot3d Package는 이 기능을 지원하지 않는데요, 혹시 이 기능을 원하신다면 3D 그래프를 회전시키면서 볼 수 있는 다른 오픈소스를 찾아보셔야 할 거예요.

 

 

 

[ 영화 Minority Report 의 한 장면 ]

 

* 출처 : http://www.bustle.com/articles/111715-will-tom-cruise-be-in-the-minority-report-tv-show-its-telling-a-different-story

 

 

 

scatterplot3d Package에 대해서 좀더 알고 싶은신 분, 다른 예제를 참고하고 싶으신 분은 아래의 Reference를 참고하시기 바랍니다.

 

[Reference] https://cran.r-project.org/web/packages/scatterplot3d/scatterplot3d.pdf

 

 

많은 도움이 되었기를 바랍니다.

 

이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡' 단추를 꾸욱 눌러주세요.^^

 

728x90
반응형
Posted by Rfriend
,

수 3개 이상의 다변량 데이터(multivariate data set)를 2차원 평면에 효과적으로 시각화할 수 있는 방법으로

 

(1) 레이더 차트 (radar chart) or 거미줄 그림(spider plot)

(2) 별 그래프 (star graph) (레이더 차트와 유사, 중심점 차이 존재)

(3) 평행 좌표 그림 (parallel coordinate plot)

(4) 3차원 산점도 (3 dimensional scatter plot)

(5) 체르노프 얼굴그림 (Chernoff faces)

(6) 산점도 행렬(scatter plot matrix)

(7) 모자이크 그림(mosaic plot)

 

등이 있습니다. 

 

산점도 행렬(http://rfriend.tistory.com/83, http://rfriend.tistory.com/82)과 모자이크 그림(http://rfriend.tistory.com/71)은 이전 포스팅을 참고하시기 바랍니다.

 

이번 포스팅에서는 (3) 평행 좌표 그림 (parallel coordinate plot)에 대해서 소개하겠습니다. 

 

MASS Package의 parcoord() 함수를 사용하겠으며, 예제 데이터 역시 MASS Package에 내장된 Cars93 데이터 프레임의 차종(Type)별로 선모양(line type)과 색깔(color)을 달리하여 가격(Price), 고속도로연비(MPG.highway), 마력(Horsepower), 분당회전수(RPM), 길이(Length), 무게(Weight) 변수를 가지고 그래프를 그려보겠습니다.

 

 

 

> ##--------------------------------------
> ## parallel coordinate plot
> ##--------------------------------------
> 
> library(MASS)
> str(Cars93)
'data.frame':	93 obs. of  27 variables:
 $ Manufacturer      : Factor w/ 32 levels "Acura","Audi",..: 1 1 2 2 3 4 4 4 4 5 ...
 $ Model             : Factor w/ 93 levels "100","190E","240",..: 49 56 9 1 6 24 54 74 73 35 ...
 $ Type              : Factor w/ 6 levels "Compact","Large",..: 4 3 1 3 3 3 2 2 3 2 ...
 $ Min.Price         : num  12.9 29.2 25.9 30.8 23.7 14.2 19.9 22.6 26.3 33 ...
 $ Price             : num  15.9 33.9 29.1 37.7 30 15.7 20.8 23.7 26.3 34.7 ...
 $ Max.Price         : num  18.8 38.7 32.3 44.6 36.2 17.3 21.7 24.9 26.3 36.3 ...
 $ MPG.city          : int  25 18 20 19 22 22 19 16 19 16 ...
 $ MPG.highway       : int  31 25 26 26 30 31 28 25 27 25 ...
 $ AirBags           : Factor w/ 3 levels "Driver & Passenger",..: 3 1 2 1 2 2 2 2 2 2 ...
 $ DriveTrain        : Factor w/ 3 levels "4WD","Front",..: 2 2 2 2 3 2 2 3 2 2 ...
 $ Cylinders         : Factor w/ 6 levels "3","4","5","6",..: 2 4 4 4 2 2 4 4 4 5 ...
 $ EngineSize        : num  1.8 3.2 2.8 2.8 3.5 2.2 3.8 5.7 3.8 4.9 ...
 $ Horsepower        : int  140 200 172 172 208 110 170 180 170 200 ...
 $ RPM               : int  6300 5500 5500 5500 5700 5200 4800 4000 4800 4100 ...
 $ Rev.per.mile      : int  2890 2335 2280 2535 2545 2565 1570 1320 1690 1510 ...
 $ Man.trans.avail   : Factor w/ 2 levels "No","Yes": 2 2 2 2 2 1 1 1 1 1 ...
 $ Fuel.tank.capacity: num  13.2 18 16.9 21.1 21.1 16.4 18 23 18.8 18 ...
 $ Passengers        : int  5 5 5 6 4 6 6 6 5 6 ...
 $ Length            : int  177 195 180 193 186 189 200 216 198 206 ...
 $ Wheelbase         : int  102 115 102 106 109 105 111 116 108 114 ...
 $ Width             : int  68 71 67 70 69 69 74 78 73 73 ...
 $ Turn.circle       : int  37 38 37 37 39 41 42 45 41 43 ...
 $ Rear.seat.room    : num  26.5 30 28 31 27 28 30.5 30.5 26.5 35 ...
 $ Luggage.room      : int  11 15 14 17 13 16 17 21 14 18 ...
 $ Weight            : int  2705 3560 3375 3405 3640 2880 3470 4105 3495 3620 ...
 $ Origin            : Factor w/ 2 levels "USA","non-USA": 2 2 2 2 2 1 1 1 1 1 ...
 $ Make              : Factor w/ 93 levels "Acura Integra",..: 1 2 4 3 5 6 7 9 8 10 ...

 

 

 

차종(Type)별로 선 모양(lty)과 선 색깔(col)을 다르게 하기 위해서 데이터 전처리를 해보겠습니다. 차종이 현재는 "Compact", "Large" 등과 같이 character 로 되어있는데요, 1, 2, ..., 6 의 numeric 으로 변환하겠습니다.

 

> # making Type_number variable to put line type and color by Car Type
> Cars93_1 <- transform(Cars93, 
+                       Type_no = ifelse(Type == "Compact", 1, 
+                                        ifelse(Type == "Large", 2, 
+                                               ifelse(Type == "Midsize", 3, 
+                                                      ifelse(Type == "Small", 4, 
+                                                             ifelse(Type == "Sporty", 5, 6)))))
+                       )
> # checking top 10 observations
> head(Cars93_1[,c("Type", "Type_no")], n=10)
      Type Type_no
1    Small       4
2  Midsize       3
3  Compact       1
4  Midsize       3
5  Midsize       3
6  Midsize       3
7    Large       2
8    Large       2
9  Midsize       3
10   Large       2
>  

 

 

 

 

이제 준비가 되었네요. MASS Package의 parcoord() 함수를 사용해서 평행 좌표 그림(parallel coordinate plot)을 그려보겠습니다. 

 

Cars93_1[, c("MPG.highway", "RPM", "Horsepower", "Weight", "Length", "Price")] 은 평행좌표그림을 그릴 대상 변수만 선별해오는 명령문입니다.

 

위에서 Cars93_1 이라는 새로운 데이터 프레임에 Type_no 라는 numeric 변수를 만들었는데요, 선 유형(lty, line type)과 색깔(col, color)를 Cars93_1$Type_no 로 지정을 해줘서 차종(Type)에 따라서 선 유형과 색깔이 달라지게 했습니다.

 

var.label = TRUE 옵션을 설정하면 각 변수별로 minimum value, maximum value 가 하단과 상단에 표기됩니다.

 

main = "parallel coordinate plot of Cars93 by Type" 옵션은 그래프에 제목 넣을 때 사용합니다.

 

아래 그래프 상단 우측에 범례가 들어가 있는데요, legend() 함수를 사용해서 추가한 것입니다.

 

> # parallel coordinate plot > library(MASS)

> parcoord(Cars93_1[, c("MPG.highway", "RPM", "Horsepower", "Weight", "Length", "Price")], 
+          lty = Cars93_1$Type_no,
+          col = Cars93_1$Type_no, 

+ var.label = TRUE, + main = "parallel coordinate plot of Cars93 by Type") > > # putting legend > legend("topright", + legend = c("Compact", "Large", "Midsize", "Small", "Sporty", "Van"), + lty = c(1:6), + col = c(1:6), + lwd = 2, # line width + cex = 0.7) # character size

 

 

 

 

다음번 포스팅에서는 3차원 산점도 (3 dimensional scatter plot)에 대해서 소개하도록 하겠습니다.

 

많은 도움 되었기를 바랍니다.

 

이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡' 단추를 꾸욱 눌러주세요.^^

 

 

728x90
반응형
Posted by Rfriend
,

수 3개 이상의 다변량 데이터(multivariate data set)를 2차원 평면에 효과적으로 시각화할 수 있는 방법으로

 

(1) 레이더 차트 (radar chart) or 거미줄 그림(spider plot)

(2) 별 그래프 (star graph) (레이더 차트와 유사, 중심점 차이 존재)

(3) 평행 좌표 그림 (parallel coordinate plot)

(4) 3차원 산점도 (3 dimensional scatter plot)

(5) 체르노프 얼굴그림 (Chernoff faces)

(6) 산점도 행렬(scatter plot matrix)

(7) 모자이크 그림(mosaic plot)

 

등이 있습니다. 

 

산점도 행렬(http://rfriend.tistory.com/83, http://rfriend.tistory.com/82)과 모자이크 그림(http://rfriend.tistory.com/71)은 이전 포스팅을 참고하시기 바랍니다.

 

이번 포스팅에서는 (2) 별 그래프 (star graph)에 대해서 소개하겠습니다. 

 

graphics Package의 stars() 함수를 사용하겠습니다.  graphics Package는 base Package로서 R 설치할 때 기본으로 설치되므로 stars() 함수를 사용하기 위해 추가로 별도 패키지 설치는 필요하지 않습니다.

 

stars() 함수는 dataframe 이나 matrix 형태의 데이터셋을 사용합니다. scale = TRUE 옵션을 사용하면 (minimum value) 0 ~ (maximum value) 1 사이의 값으로 다변량 변수들의 값을 표준화해줍니다.  별 그래프(star graph)의 기본 원리는 중심점(center point)으로 부터 각 관측치별/ 각 변수별로 거리(distance) 혹은 반지름(radius)이 얼마나 떨어져있는가를 시각화한 것입니다.

 

실습을 위해서 MASS Package에 내장된 Cars93 dataframe을 사용하겠습니다. 이전 포스팅 레이더 차트(radar chart) 와 비교하기 쉽도록 이번에도 차종(Type), 가격(Price), 고속도로연비(MPG.highway), 마력(Horsepower), 분당회전수(RPM), 길이(Length), 무게(Weight) 의 7개 변수를 똑같이 사용하겠습니다.

 

> library(MASS)
> str(Cars93)
'data.frame':	93 obs. of  27 variables:
 $ Manufacturer      : Factor w/ 32 levels "Acura","Audi",..: 1 1 2 2 3 4 4 4 4 5 ...
 $ Model             : Factor w/ 93 levels "100","190E","240",..: 49 56 9 1 6 24 54 74 73 35 ...
 $ Type              : Factor w/ 6 levels "Compact","Large",..: 4 3 1 3 3 3 2 2 3 2 ...
 $ Min.Price         : num  12.9 29.2 25.9 30.8 23.7 14.2 19.9 22.6 26.3 33 ...
 $ Price             : num  15.9 33.9 29.1 37.7 30 15.7 20.8 23.7 26.3 34.7 ...
 $ Max.Price         : num  18.8 38.7 32.3 44.6 36.2 17.3 21.7 24.9 26.3 36.3 ...
 $ MPG.city          : int  25 18 20 19 22 22 19 16 19 16 ...
 $ MPG.highway       : int  31 25 26 26 30 31 28 25 27 25 ...
 $ AirBags           : Factor w/ 3 levels "Driver & Passenger",..: 3 1 2 1 2 2 2 2 2 2 ...
 $ DriveTrain        : Factor w/ 3 levels "4WD","Front",..: 2 2 2 2 3 2 2 3 2 2 ...
 $ Cylinders         : Factor w/ 6 levels "3","4","5","6",..: 2 4 4 4 2 2 4 4 4 5 ...
 $ EngineSize        : num  1.8 3.2 2.8 2.8 3.5 2.2 3.8 5.7 3.8 4.9 ...
 $ Horsepower        : int  140 200 172 172 208 110 170 180 170 200 ...
 $ RPM               : int  6300 5500 5500 5500 5700 5200 4800 4000 4800 4100 ...
 $ Rev.per.mile      : int  2890 2335 2280 2535 2545 2565 1570 1320 1690 1510 ...
 $ Man.trans.avail   : Factor w/ 2 levels "No","Yes": 2 2 2 2 2 1 1 1 1 1 ...
 $ Fuel.tank.capacity: num  13.2 18 16.9 21.1 21.1 16.4 18 23 18.8 18 ...
 $ Passengers        : int  5 5 5 6 4 6 6 6 5 6 ...
 $ Length            : int  177 195 180 193 186 189 200 216 198 206 ...
 $ Wheelbase         : int  102 115 102 106 109 105 111 116 108 114 ...
 $ Width             : int  68 71 67 70 69 69 74 78 73 73 ...
 $ Turn.circle       : int  37 38 37 37 39 41 42 45 41 43 ...
 $ Rear.seat.room    : num  26.5 30 28 31 27 28 30.5 30.5 26.5 35 ...
 $ Luggage.room      : int  11 15 14 17 13 16 17 21 14 18 ...
 $ Weight            : int  2705 3560 3375 3405 3640 2880 3470 4105 3495 3620 ...
 $ Origin            : Factor w/ 2 levels "USA","non-USA": 2 2 2 2 2 1 1 1 1 1 ...
 $ Make              : Factor w/ 93 levels "Acura Integra",..: 1 2 4 3 5 6 7 9 8 10 ...

 

 

 

 

93개의 차량 관측치가 있는데요, 이것을 6개의 차종(Type)을 기준으로 평균 통계량으로 요약한 후에, 차종별로 6개의 평균치 다변량 변수를 가지고 별 그래프를 그려보겠습니다.

 

> # cross tabulation by Car Type
> table(Cars93$Type)

Compact   Large Midsize   Small  Sporty     Van 
     16      11      22      21      14       9
> 
> # mean of multivariates by Car Type
> install.packages("doBy")
> library(doBy)
> 
> mean_by_Type <- summaryBy(MPG.highway + RPM + Horsepower + Weight + Length + Price ~ Type, 
+                           data=Cars93, 
+                           FUN = c(mean))
> 
> mean_by_Type
     Type MPG.highway.mean RPM.mean Horsepower.mean Weight.mean Length.mean Price.mean
1 Compact         29.87500 5362.500        131.0000    2918.125    182.1250   18.21250
2   Large         26.72727 4672.727        179.4545    3695.455    204.8182   24.30000
3 Midsize         26.72727 5336.364        173.0909    3400.000    192.5455   27.21818
4   Small         35.47619 5633.333         91.0000    2312.857    167.1905   10.16667
5  Sporty         28.78571 5392.857        160.1429    2899.643    175.2143   19.39286
6     Van         21.88889 4744.444        149.4444    3830.556    185.6667   19.10000

 

 

 

 

stars() 함수에서는 rownames 를 가져다가 labeling 을 합니다.  현재 rownames 는 1, 2,..., 6 의 숫자로 되어있으므로, 이를 차종(Type) 이름으로 변경하도록 하겠습니다. (굷게 파란색으로 밑줄친 부분)

 

> # creating row names with Type
> rownames(mean_by_Type) <- mean_by_Type$Type
> 
> mean_by_Type
           Type MPG.highway.mean RPM.mean Horsepower.mean Weight.mean Length.mean Price.mean
Compact Compact         29.87500 5362.500        131.0000    2918.125    182.1250   18.21250
Large     Large         26.72727 4672.727        179.4545    3695.455    204.8182   24.30000
Midsize Midsize         26.72727 5336.364        173.0909    3400.000    192.5455   27.21818
Small     Small         35.47619 5633.333         91.0000    2312.857    167.1905   10.16667
Sporty   Sporty         28.78571 5392.857        160.1429    2899.643    175.2143   19.39286
Van         Van         21.88889 4744.444        149.4444    3830.556    185.6667   19.10000

 

 

 

 

위에서 rownames() 로 뭐가 바뀌었나 잘 모를수도 있는데요, 아래에 화면 캡쳐한 그래프를 참고하시기 바랍니다. 제일 왼쪽에 rowname 이 숫자에서 차종(Type)으로 바뀐게 보이지요?

 

 

 

 

doBy Package로 요약통계량을 생성하면 변수명 뒤에 자동으로 통계량 이름이 따라 붙습니다. 이번 예제의 경우에는 평균을 구했으므로 MPG.highway.mean, RPM.mean, ... 이런 식으로요.  변수명이 너무 길다보니 나중에 labeling 할 때 옆으로 삐죽 튀어나가서 보기 싫어서요, 변수명을 좀더 짧게 변경해보겠습니다. 변수명 뒤에 .mean 을 생략하고 사용하겠습니다.  위에 rownames() 함수는 stars() 함수를 사용하려면 꼭 해줘야 하는 것이구요, 아래의 renames()는 필수사항은 아닙니다.

 

 

> # renaming of variables
> library(reshape)
> mean_by_Type <- rename(mean_by_Type, 
+                        c(MPG.highway.mean = "MPG.highway",  
+                          RPM.mean = "RPM",  
+                          Horsepower.mean = "Horsepower",  
+                          Weight.mean = "Weight", 
+                          Length.mean = "Length", 
+                          Price.mean = "Price"
+                          )
+                        )
> mean_by_Type
           Type MPG.highway      RPM Horsepower   Weight   Length    Price
Compact Compact    29.87500 5362.500   131.0000 2918.125 182.1250 18.21250
Large     Large    26.72727 4672.727   179.4545 3695.455 204.8182 24.30000
Midsize Midsize    26.72727 5336.364   173.0909 3400.000 192.5455 27.21818
Small     Small    35.47619 5633.333    91.0000 2312.857 167.1905 10.16667
Sporty   Sporty    28.78571 5392.857   160.1429 2899.643 175.2143 19.39286
Van         Van    21.88889 4744.444   149.4444 3830.556 185.6667 19.10000

 

 

 

이제 드디어 데이터셋이 준비가 되었습니다.  stars() 함수를 사용해서 별 그래프를 그려보겠습니다.

 

stars(x, ...) 의 x 자리에는 dataframe 이나 matrix 형태의 다변량 데이터셋 이름을 입력하면 됩니다.

locations = NULL, nrow = 2, ncol = 4 옵션은 행이 2줄, 열이 4줄인 square layout 으로 배열하라는 뜻입니다.

scale = TRUE 는 변수별로 단위(scale)가 달라서 들쭉날쭉한 값들을 변수별로 모두 최소값 0 ~ 최대값 1 사이로 변수별 값들을 표준화(standardization) 합니다.

full = TRUE 로 지정하면 360도의 전체 원으로 그래프를 그립니다. full = FALSE 로 지정하면 1180도짜리 반원(semi-circle)으로 그래프가 그려집니다.

radius = TRUE 로 지정하면 반지름 선이 그려집니다. 만약 radius = FALSE 로 하면 반지름 선이 안그려지는데요, 보기에 좀 휑~합니다. ^^'

frame.plot = TRUE 로 하면 그래프의 외곽에 네모 박스 선으로 테두리가 쳐집니다.

main 은 제목을 입력하는 옵션입니다. sub 는 부제목 입력하는 옵션이구요.

cex 는 글자 크기 지정하는 옵션인데요, default 가 1이고 숫자가 커질 수록 글자 크기가 커집니다.

lwd 는 선 두께 (line width) 지정하는 옵션입니다. default 가 1이며, 숫자가 커질 수록 선이 두꺼워집니다.

key.loc = c(7.5, 1.5) 는 x, y 좌표 위치에 각 변수들의 이름(unit key)을 범례로 집어넣습니다.

 

말로 설명해놓긴 했는데요, 잘 이해가 안갈수도 있겠습니다.  아래에 stars() 함수를 복사해놓고서 옵션마다 하나씩 '#'을 붙여가면서 실행을 해보시기 바랍니다.  그러면 '#'을 붙이기 전과 비교가 될테고, 옵션별 기능을 바로 확인할 수 있습니다.

 

> # star plot > stars(mean_by_Type[, 2:7], # dataframe or matrix + locations = NULL, # locations = NULL, the segment plots will be placed in a rectangular grid + nrow = 2, # number of rows at a square layout (w/locations = NULL) + ncol = 4, # number of columns at a square layout (w/locations = NULL) + scale = TRUE, # the columns are scaled independently (max in each column: 1, min: 0) + full = TRUE, # TRUE: occupy a full circle, FALSE : semi-circle + radius = TRUE, # the radii corresponding to each variable in the data will be drawn + frame.plot = TRUE, # if TRUE, the plot region is framed + main = "Star plot - means of multivariate by Car Type", # a main title for the plot + cex = 1, # size of label character (by default, cex = 1) + # labels = NULL # if NULL, no attempt is made to construct labels + lwd = 1, # line width (by default, lwd = 1) + key.loc = c(7.5, 1.5) # vector with x and y coordinates of the unit key + )

 

 

 

 

 

 

[ stars() 함수로 radar chart 그리기 ]

 

이전 포스팅에서 소개했던 레이더 차트 or 거미줄 그림(radar chart, or spider plot)도 stars() 함수로 그릴 수 있습니다. 별 그래프(star plot)이 개별 관측치마다 location을 부여하여 하나씩 다변량 그래프를 그린 것이라면, 레이더 차트(radar chart) or 거미줄 그림(spider plot)은 하나의 공통된 location을 중심점으로 하여 관측치들을 중첩하여 그린 다변량 그래프입니다.  locations = c(0, 0)으로 중심점을 한개로 통일하였고,  key.loc = c(0, 0) 으로 똑같이 지정해주어서 이 중심점 좌표를 기준으로 변수명을 labeling 할 수 있게 하였습니다.

 

radius = FALSE 로 바꾸어서 반지름 선은 표시하지 않게끔 하였습니다. 6개 차종(Type)의 그래프가 중첩이 되다보니 radius = TRUE 로 했더니 선이 겹쳐서 아예 안보이는게 있어서요.

 

관치치들의 다변량 변수 간에 존재하는 패턴에 대해서 관심이 있는 분석가라면 아무래도 그룹별로 선 색깔을 달리하여 그린 레이더 차트 (or 거미줄 그림)가 별 그래프(star chart)보다는 좀더 유용한 편입니다. col.lines = c(1:6) 옵션으로 6개 차종(Type)별 색깔을 구분하였습니다.

 

범례(legend)는 legend(x= , y= , ...) 함수로 추가를 하였습니다. x, y 좌표는 몇 번 숫자를 넣어보고 시행착오를 거치면서 적당한 좌표를 찾아나가야 합니다. "topright", "topleft" 이런 식으로 범례 좌표를 지정했더니 레이더 차트랑 자꾸 겹쳐서요. ^^;

 

> # radar chart (or spider chart) 
> stars(mean_by_Type[, 2:7], 
+       locations = c(0, 0), 
+       key.loc = c(0, 0), 
+       scale = TRUE, 
+       radius = FALSE, 
+       cex = 1, 
+       lty = 2, 
+       col.lines = c(1:6), 
+       lwd = 2, 
+       main = "radar chart - means of multivariate by Car Type" 
+       )
> 
> legend(x=1, y=1, legend = mean_by_Type$Type, lty = 2, col = c(1:6), lwd = 2)

 

 

 

 

 

위에 stars() 함수로 레이더 차트를 그리기는 했는데요, 이전 포스팅에서 fmsb Package의 radarchart() 함수로 그린 radar chart 보다는 가독성이 좀 떨어져보입니다.

 

여러개의 그룹을 레이더 차트 (radar chart)로 보려면 fmsb Package의 radarchart() 함수를 사용하고, 개별 그룹 단위로 분리해서 보려면 graphics Package의 stars() 함수로 별 그림 (star plot)을 그려서 보면 좋을 것 같습니다.

 

다음 번에는 평행 좌표 그림 (parallel coordinate plot)에 대해서 알아보겠습니다.

 

많은 도움 되었기를 바랍니다.

 

이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡' 단추를 꾸욱 눌러주세요.^^

 

728x90
반응형
Posted by Rfriend
,

실전 업무에서는 다변량 데이터(multivariate data set)를 사용하는 경우가 다반사입니다. 그리고 분석업무 초반에 탐색적 분석을 수행할 때 시각화를 통해 변수들 간의 관계, 패턴을 탐색하는 분석 기법이 굉장히 유용합니다.

 

하지만 다변량 데이터 중에서도 특히 3개 이상의 변수를 가지는 다변량 데이터의 경우 그동안 소개해드렸던 히스토그램, 막대그림, 박스 그림, 산점도, 선그림/시계열 그림 등을 활용해서 2차원 평면에 나타낼 수 없는 한계가 있습니다. (물론, 색깔이라든지 모양을 데이터 그룹 별로 달리하면 3차원, 4차원의 정보를 시각화할 수 있기는 합니다만...)

 

변수 3개 이상의 다변량 데이터를 2차원 평면에 효과적으로 시각화할 수 있는 방법으로

 

(1) 레이더 차트 (radar chart) or 거미줄 그림(spider plot)

(2) 별 그림 (star graph) (레이더 차트와 유사, 중심점 다름)

(3) 평행 좌표 그림 (parallel coordinate plot)

(4) 3차원 산점도 (3 dimensional scatter plot)

(5) 체르노프 얼굴그림 (Chernoff faces)

(6) 산점도 행렬(scatter plot matrix)

(7) 모자이크 그림(mosaic plot)

 

등이 있습니다. 

산점도 행렬(http://rfriend.tistory.com/83, http://rfriend.tistory.com/82)과 모자이크 그림(http://rfriend.tistory.com/71)은 이전 포스팅을 참고하시기 바랍니다.

 

이번 포스팅에서는 (1) 레이더 차트 (radar chart)에 대해서 소개하겠습니다. 방사형의 레이더 차트가 마치 거미줄을 닮아서 거미줄 그림 (spider plot)이라고도 부릅니다.

 

별 그림 (star plot) 도 레이더 차트와 형태는 거의 유사한데요, 약간 현태가 다른 점이 있고 stars 라는 R 패키지가 별도로 있고 해서 다음번에 따로 설명을 드리겠습니다.

 

R 실습에 사용할 데이터는 MASS 패키지에 내장되어 있는 Cars93 데이터프레임입니다. 분석 대상 변수로는 차 유형(Type), 가격(Price), 고속도로연비(MPG.highway), 마력(Horsepower), 분당회전수RPM(RPM), 길이(Length), 무게(Weight) 등의 7개 변수입니다.

 

> library(MASS)
> str(Cars93)
'data.frame':	93 obs. of  27 variables:
 $ Manufacturer      : Factor w/ 32 levels "Acura","Audi",..: 1 1 2 2 3 4 4 4 4 5 ...
 $ Model             : Factor w/ 93 levels "100","190E","240",..: 49 56 9 1 6 24 54 74 73 35 ...
 $ Type              : Factor w/ 6 levels "Compact","Large",..: 4 3 1 3 3 3 2 2 3 2 ...
 $ Min.Price         : num  12.9 29.2 25.9 30.8 23.7 14.2 19.9 22.6 26.3 33 ...
 $ Price             : num  15.9 33.9 29.1 37.7 30 15.7 20.8 23.7 26.3 34.7 ...
 $ Max.Price         : num  18.8 38.7 32.3 44.6 36.2 17.3 21.7 24.9 26.3 36.3 ...
 $ MPG.city          : int  25 18 20 19 22 22 19 16 19 16 ...
 $ MPG.highway       : int  31 25 26 26 30 31 28 25 27 25 ...
 $ AirBags           : Factor w/ 3 levels "Driver & Passenger",..: 3 1 2 1 2 2 2 2 2 2 ...
 $ DriveTrain        : Factor w/ 3 levels "4WD","Front",..: 2 2 2 2 3 2 2 3 2 2 ...
 $ Cylinders         : Factor w/ 6 levels "3","4","5","6",..: 2 4 4 4 2 2 4 4 4 5 ...
 $ EngineSize        : num  1.8 3.2 2.8 2.8 3.5 2.2 3.8 5.7 3.8 4.9 ...
 $ Horsepower        : int  140 200 172 172 208 110 170 180 170 200 ...
 $ RPM               : int  6300 5500 5500 5500 5700 5200 4800 4000 4800 4100 ...
 $ Rev.per.mile      : int  2890 2335 2280 2535 2545 2565 1570 1320 1690 1510 ...
 $ Man.trans.avail   : Factor w/ 2 levels "No","Yes": 2 2 2 2 2 1 1 1 1 1 ...
 $ Fuel.tank.capacity: num  13.2 18 16.9 21.1 21.1 16.4 18 23 18.8 18 ...
 $ Passengers        : int  5 5 5 6 4 6 6 6 5 6 ...
 $ Length            : int  177 195 180 193 186 189 200 216 198 206 ...
 $ Wheelbase         : int  102 115 102 106 109 105 111 116 108 114 ...
 $ Width             : int  68 71 67 70 69 69 74 78 73 73 ...
 $ Turn.circle       : int  37 38 37 37 39 41 42 45 41 43 ...
 $ Rear.seat.room    : num  26.5 30 28 31 27 28 30.5 30.5 26.5 35 ...
 $ Luggage.room      : int  11 15 14 17 13 16 17 21 14 18 ...
 $ Weight            : int  2705 3560 3375 3405 3640 2880 3470 4105 3495 3620 ...
 $ Origin            : Factor w/ 2 levels "USA","non-USA": 2 2 2 2 2 1 1 1 1 1 ...
 $ Make              : Factor w/ 93 levels "Acura Integra",..: 1 2 4 3 5 6 7 9 8 10 ...
> 

 

 

먼저 table() 함수를 사용하여 차 유형별 분할표를 만들어보았습니다.  6종류의 차 유형별로 10~20여대씩 분포하고 있음을 알 수 있습니다.

 

 

> # cross tabulation by car type

> table(Cars93$Type)

Compact   Large Midsize   Small  Sporty     Van 
     16      11      22      21      14       9
 

 

 

 

다음으로, 차 유형(Type)별로 가격(Price), 고속도로연비(MPG.highway), 마력(Housepower), 분당회전수RPM(RPM), 길이(Length), 무게(Weight) 등 6개 변수별 평균(mean)을 구해보겠습니다.

 

doBy package 의 summaryBy() 함수를 사용하면 연속형변수의 다변량 데이터에 일괄적으로 요약통계량을 편리하게 계산할 수 있습니다. Base package가 아니므로 install.packages("doBy")로 설치하시고, library(doBy)로 호출한 후에 summaryBy() 함수의 FUN = c(mean, min, max, sd, ...) 처럼 원하는 통계량 함수를 입력하면 됩니다. 이번에는 평균만 사용할 것이므로 아래 예에서는 FUN = c(mean) 만 입력하였습니다.

 

> # mean of multivariates by Car Type
> install.packages("doBy")
Installing package into ‘C:/Users/user/Documents/R/win-library/3.2’
(as ‘lib’ is unspecified)
trying URL 'http://cran.rstudio.com/bin/windows/contrib/3.2/doBy_4.5-14.zip'
Content type 'application/zip' length 3419973 bytes (3.3 MB)
downloaded 3.3 MB

package ‘doBy’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
	C:\Users\user\AppData\Local\Temp\RtmpGGgn4j\downloaded_packages
> library(doBy)
필요한 패키지를 로딩중입니다: survival
Warning message:
패키지 ‘doBy’는 R 버전 3.2.3에서 작성되었습니다 
> 
> mean_by_Type <- summaryBy(MPG.highway + RPM + Horsepower + Weight + Length + Price ~ Type, 
+           data=Cars93, 
+           FUN = c(mean))
> 
> 
> mean_by_Type

     Type MPG.highway.mean RPM.mean Horsepower.mean Weight.mean Length.mean Price.mean
1 Compact         29.87500 5362.500        131.0000    2918.125    182.1250   18.21250
2   Large         26.72727 4672.727        179.4545    3695.455    204.8182   24.30000
3 Midsize         26.72727 5336.364        173.0909    3400.000    192.5455   27.21818
4   Small         35.47619 5633.333         91.0000    2312.857    167.1905   10.16667
5  Sporty         28.78571 5392.857        160.1429    2899.643    175.2143   19.39286
6     Van         21.88889 4744.444        149.4444    3830.556    185.6667   19.10000

 

 

 

 

다음으로, 레이더 차트(radar chart)를 그리려면 fmsb Package 를 사용합니다. install.packages("fmsb")로 설치하고, library(fmsb)로 호출해보겠습니다.

 

> install.packages("fmsb")
Installing package into ‘C:/Users/user/Documents/R/win-library/3.2’
(as ‘lib’ is unspecified)
trying URL 'http://cran.rstudio.com/bin/windows/contrib/3.2/fmsb_0.5.2.zip'
Content type 'application/zip' length 214358 bytes (209 KB)
downloaded 209 KB

package ‘fmsb’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
	C:\Users\user\AppData\Local\Temp\RtmpGGgn4j\downloaded_packages
> library(fmsb)
Warning message:
패키지 ‘fmsb’는 R 버전 3.2.3에서 작성되었습니다

 

 

 

 

fmsb Package의 radarchart() 함수를 사용하기 위한 데이터 형태는

(1) 데이터 구조는 Dataframe

(2) 첫번째 행(1st row)에 최대값(max value)

(3) 두번째 행(2nd row)에 최소값(min value)

(4) 세번째 행부터는 원래의 관측값

이 오도록 데이터를 전처리해주어야 합니다.

 

 

[ fmsb Package의 radrchart() 함수 사용하기 위한 데이터 준비 ]

 

 

 

 

R 사용자정의함수로 첫번째 행에 최대값, 두번째 행에 최소값이 오도록 하여 Dataframe으로 묶는 명령어는 아래와 같습니다. 

 

사용자정의함수에 더하여 scale() 함수를 사용해서 6개의 변수를 표준화 하였습니다.

 

> # manipulating dataset for radar chart

> # data frame includes possible maximum values as row 1 
> # and possible minimum values as row 2

> df_radarchart <- function(df) { + df <- data.frame(df) + dfmax <- apply(df, 2, max) + dfmin <- apply(df, 2, min) + as.data.frame(rbind(dfmax, dfmin, df)) + } >

> # maximum value as row 1, minimum value as row 2 : user-defined function df_radarchart

> # standardization : scale()

> mean_by_Type_trans <- df_radarchart(scale(mean_by_Type[,c(2:7)]))

> 

> mean_by_Type_scale MPG.highway.mean RPM.mean Horsepower.mean Weight.mean Length.mean Price.mean 1 2.6145692 2.1399576 1.98554516 2.1439959 2.53293142 2.2793069 2 -2.4199059 -2.3321490 -2.73029381 -2.5089822 -2.31904165 -2.6344948 11 0.3636458 0.4429717 -0.50216519 -0.4509575 -0.18708691 -0.2596045 21 -0.3393415 -1.3321490 0.98554516 0.9078356 1.53293142 0.7806413 3 -0.3393415 0.3757101 0.79016106 0.3913731 0.60272622 1.2793069 4 1.6145692 1.1399576 -1.73029381 -1.5089822 -1.31904165 -1.6344948 5 0.1203738 0.5210954 0.39261423 -0.4832648 -0.71088103 -0.0579024 6 -1.4199059 -1.1475858 0.06413856 1.1439959 0.08135194 -0.1079465

 

 

 

 

드디어 radarchart() 함수를 사용해서 레이더 차트를 그려보겠습니다. 각 옵션에 대한 기능은 아래 R 명령어에 부가설명을 달아놓았습니다.

 

범례는 legend() 함수를 사용해서 왼쪽 상단에 추가하였습니다.

 

> # radar chart (or spider plot)
> radarchart(df = mean_by_Type_scale, # The data frame to be used to draw radarchart
+            seg = 6, # The number of segments for each axis 
+            pty = 16, # A vector to specify point symbol: Default 16 (closed circle)
+            pcol = 1:6, # A vector of color codes for plot data
+            plty = 1:6, # A vector of line types for plot data
+            plwd = 2, # A vector of line widths for plot data
+            title = c("radar chart by Car Types") # putting title at the top-middle
+            )
> 

> # adding legend

> legend("topleft", legend = mean_by_Type$Type, col = c(1:6), lty = c(1:6), lwd = 2)

 

 

 

 

 

 

선의 형태(plty)나 선의 색깔(pcol)을 프로그래밍 편하라고 1:6 이라고 했는데요, 원하는 선 모양이나 색깔을 순서대로 지정할 수 있습니다. 

 

다음번 포스팅에서는 별 그림(star graph)에 대해서 알아보겠습니다.

 

많은 도움 되어기를 바랍니다.

 

이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡' 단추를 꾸욱 눌러주세요.^^

 

 

728x90
반응형
Posted by Rfriend
,

수집한 데이터셋의 관측치들 간에 중복(duplication)이 있는 경우가 있습니다.  혹은 여러개의 흩어져 있는 데이터셋을 특정 기준 변수(key)를 사용해서 병합(merge)하는 전처리 작업을 하다 보면 가끔씩 의도하지 않게 중복데이터가 생기는 수가 있습니다.  서로 다른 행인데 각 변수별 관측값들이 동일한 경우 말이지요.  이럴 경우 저장 공간을 중복되는 만큼 더 잡아먹는고 데이터 처리 속도가 더 걸린다는 문제가 있으며, 더 심각하게는 이러한 데이터셋을 그대로 두고 통계 분석을 진행할 경우 분석 결과에 왜곡이 생길 수도 있으므로 중복 관측값 전처리가 필요합니다. (가령, 평균만 하더라도 중복이 있는 관측치가 여럿 있을 경우 분자의 관측치 합과 분모의 관측치 개수가 중복 제거후와는 서로 달라지겠지요?)

 

중복 데이터가 있을 경우에는 먼저 한개의 유일한 관측치(unique elements)만을 남겨놓고 나머지 중복 데이터들은 제거하는 전처리를 거쳐야 합니다. 이를 위해 R의

 

- {base} 패키지 : unique()

- {base} 패키지 : dataframe[!duplicated(var), ]

- {dplyr} 패키지 : distinct()

 

함수를 사용할 수 있습니다.

 

SAS 사용자라면 datastep에서 특정 변수를 기준으로 sorting을 한 후에 first.variable_name 또는 last.variable_name 명령문을 사용했던 것을 생각하시면 이해하기 쉬울 것입니다.  SAS와는 다르게 R은 sorting을 할 필요가 없습니다. (SAS는 merge 할 때도 먼저 sorting을 해줘야 하는 반면, R은 merge 할 때 sorting 해줄 필요 없습니다)

 

단, unique도 그렇고, merge도 그렇고 크기가 작은 데이터셋에는 별 무리가 없지만 대용량 데이터셋에 사용하기에는 처리 성능에 부담이 아주 많이 되는 함수입니다.  수십 기가가 넘는 대용량 사이즈의 데이터셋이라면 하둡 클러스터 내에서 Hive 등으로 중복 데이터 전처리하여 사용하시길 권합니다.

 

 

 

[ 중복없이 유일한 관측치만 남기기 (extracting unique elements) ]

 

 

 

 

R의 unique() 함수는 base package 함수에 내장되어 있으므로 별도의 패키지를 설치할 필요는 없습니다.  데이터 프레임(data frame), 배열(array), 행렬(matrix), 벡터(vector)에 모두 사용할 수 있는데요, 일반적으로 데이터 프레임을 분석에 많이 사용하므로 아래에는 데이터 프레임을 대상으로 unique() 함수 사용하는 방법을 소개하겠습니다.  

 

 

먼저 R 실습을 위해 관측치들 간에 중복이 포함되어 있는 변수 3개짜리 데이터 프레임을 만들어 보겠습니다.

 

> ##------------------------------------------
> ## extracting unique elements : unique()
> ##------------------------------------------
> 
> a1 <- rep(1:10, each = 2)
> a1
 [1]  1  1  2  2  3  3  4  4  5  5  6  6  7  7  8  8  9  9 10 10
> 
> a2 <- rep(c(1, 3, 5, 7, 9), each = 4)
> a2
 [1] 1 1 1 1 3 3 3 3 5 5 5 5 7 7 7 7 9 9 9 9
> 
> a3 <- c(1, 1, 1, 1, 3, 3, 3, 3, 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 11, 12)
> a3
 [1]  1  1  1  1  3  3  3  3  5  5  6  6  7  7  8  8  9 10 11 12
> 
> a1a2a3 <- data.frame(cbind(a1, a2, a3))
> a1a2a3
   a1 a2 a3
1   1  1  1
2   1  1  1
3   2  1  1
4   2  1  1
5   3  3  3
6   3  3  3
7   4  3  3
8   4  3  3
9   5  5  5
10  5  5  5
11  6  5  6
12  6  5  6
13  7  7  7
14  7  7  7
15  8  7  8
16  8  7  8
17  9  9  9
18  9  9 10
19 10  9 11
20 10  9 12
> 
> str(a1a2a3)
'data.frame':	20 obs. of  3 variables:
 $ a1: num  1 1 2 2 3 3 4 4 5 5 ...
 $ a2: num  1 1 1 1 3 3 3 3 5 5 ...
 $ a3: num  1 1 1 1 3 3 3 3 5 5 ...

 

 

 

 

[예제 1]

변수가 3개 있는 데이터 프레임인데요, a1과 a2의 두 개 변수를 기준으로 중복여부를 체크한 후에, 중복이 있을 경우에는 1개만 선택하고 나머지 중복된 관측치는 제거하는 방법에 대한 예시는 아래와 같습니다.

 

>

> # extracting unique elements by 2 variables > aqa2a3_uniq_var2 <- unique(a1a2a3[, c("a1", "a2")]) > aqa2a3_uniq_var2 a1 a2 1 1 1 3 2 1 5 3 3 7 4 3 9 5 5 11 6 5 13 7 7 15 8 7 17 9 9 19 10 9

 

 

 

 

위의 예제에서 "a1"변수와 "a2" 변수를 기준으로 중복 관측치를 제거하고 유일한 관측치만 남기는 처리 개념을 풀어서 설명하면 아래와 같습니다.  참고로, a1a2a3[, c("a1", "a2")] 은 a1a2a3 데이터 프레임에서 변수 "a1"과 "a2"만 select 하라는 뜻입니다.

 

 

 

 


 

 

[예제 2]

다음으로, "a1", "a2", "a3" 세 개의 변수를 기준으로 중복된 관측치가 있다면 유일한 관측치만 남기고 나머지 중복 관측치는 제거하는 예를 들어보겠습니다.

 

> 

> # extracting unique elements by 3 variables > aqa2a3_uniq_var3 <- unique(a1a2a3[, c("a1", "a2", "a3")]) > aqa2a3_uniq_var3 a1 a2 a3 1 1 1 1 3 2 1 1 5 3 3 3 7 4 3 3 9 5 5 5 11 6 5 6 13 7 7 7 15 8 7 8 17 9 9 9 18 9 9 10 19 10 9 11 20 10 9 12

 

 

 

 

위 R 함수의 처리 과정을 풀어보면 아래와 같습니다.

 

 

 

 

"a1", "a2"의 두 개 변수만을 기준으로 했을 때 대비, "a1", "a2", "a3"의 세 개변수를 기준으로 unique() 함수를 적용했을 때 18번째와 20번째 행이 중복없는 유일한 행으로서 추가로 살아남았음을 알 수 있습니다.

 

 

 


 

[예제 3]

unique(x, fromLast = TRUE) 옵션을 적용하면 중복된 관측치들 중에서 남길 관측치(행, row)를 선택할 때 가장 밑에 있는 관측치(from Last observation)를 기준으로 선택합니다. default 는 fromLast = FALSE 입니다.

 

> 
> # identical element will be kept from the last : fromLast = TRUE 
> # defaulu : fromLast = FALSE
> aqa2a3_uniq_var3_fromLast <- unique(a1a2a3[, c("a1", "a2", "a3")], fromLast = TRUE) 
> aqa2a3_uniq_var3_fromLast  # differnt order
   a1 a2 a3
2   1  1  1
4   2  1  1
6   3  3  3
8   4  3  3
10  5  5  5
12  6  5  6
14  7  7  7
16  8  7  8
17  9  9  9
18  9  9 10
19 10  9 11
20 10  9 12

 

 

 

 

 

[예제2]의 fromLast = FALSE (default 이므로 특별히 명기할 필요는 없음) 일 때와 [예제3]의 fromLast = TRUE 일 때의 차이가 무엇인지 잘 이해가 안 갈 수도 있는데요, 아래 [예제2]와 [예제3]의 데이터프레임들의 row names 의 번호가 서로 다름을 알 수 있습니다. 

 

1번째 행과 2번째 행이 중복된 것의 처리에 대해서만 설명드리자면, [예제2]의 fromLast = FALSE의 경우1번 행(first row)을 가져왔고, [예제3]의 fromLast = TRUE 의 경우 2버 행(second row)를 유일한 행으로 가져왔습니다.

 

 

 

 

[예제2]와 [예제3]의 결과는 동일합니다. 그런데 왜 굳이 이런것이 필요하지 싶을 것입니다. ^^?

위의 예제는 설명의 편의를 위해서 변수 3개 짜리 중복 데이터셋을 초간단으로 만들어본 것인데요, 실전에서 사용하는 데이터셋은 변수가 수십, 수백개, 관측치(행의 개수)도 수천, 수만, 수백만개인 경우가 다반사입니다.  이때 특정 변수를 기준으로 중복인 경우 유일한 관측치를 선별하고, 나머지 변수들은 그대로 사용해야 하는 경우 중복된 관측치의 first observation을 살려둘지 아니면 last obsetvation을 살려둘지에 따라서 중복 제거 기준 변수 이외의 타 변수들의 관측치 값들이 다른 경우에는 고민 좀 해야겠지요?  이럴 경우에 fromLast = FALSE/TRUE 옵션이 필요합니다.  (이럴 경우 SAS처럼 미리 특정 변수를 기준으로 정렬해놔야 겠군요)

 

 


 

 

{base} package에 내장되어 있는 duplicated() 함수를 사용해서 중복값을 제거하고 유일한 값만 선별할 수도 있습니다.  duplicated() 함수를 사용하면 아래 예시처럼 중복되는 행에 대해서 TRUE, FALSE boolean 값을 반환합니다.  이 논리형 값을 가지고 dataframe에서 indexing을 해오는 방식으로 중복값을 처리하고 유일한 값만 남겨놓을 수 있습니다.

 

 

> ##-----------------------
> ## duplicated() function
> ##-----------------------
> 
> # original dataset
> a1a2a3
   a1 a2 a3
1   1  1  1
2   1  1  1
3   2  1  1
4   2  1  1
5   3  3  3
6   3  3  3
7   4  3  3
8   4  3  3
9   5  5  5
10  5  5  5
11  6  5  6
12  6  5  6
13  7  7  7
14  7  7  7
15  8  7  8
16  8  7  8
17  9  9  9
18  9  9 10
19 10  9 11
20 10  9 12
> 
> 
> # returning TRUE for duplicated value
> duplicated(a1a2a3$a1) 
 [1] FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE
[12]  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE
> 
> 
> # indexing unduplicated rows using dataframe[!duplicated(dataframe$var1), ]
> a1a2a3_not_duplicated_var1 <- a1a2a3[!duplicated(a1a2a3$a1),]
> a1a2a3_not_duplicated_var1
   a1 a2 a3
1   1  1  1
3   2  1  1
5   3  3  3
7   4  3  3
9   5  5  5
11  6  5  6
13  7  7  7
15  8  7  8
17  9  9  9
19 10  9 11
> 
> # another exmaple
> a1a2a3[!duplicated(a1a2a3$a2),]
   a1 a2 a3
1   1  1  1
5   3  3  3
9   5  5  5
13  7  7  7
17  9  9  9

 

 

 


 

dplyr 패키지의 distinct() 함수도 중복이 없는 유일한 값을 반환합니다.  dplyr 패키지의 distinct() 가 깔끔하기도 하고, dplyr 패키지 내의 여러 데이터 전처리 함수를 함께 이용할 수 있어서 알아두시면 좋겠습니다.

 

 

 



10억 개의 정수 값에 대해 base 패키지의 unique(), duplicated() 함수와 dplyr패키지의 distinct() 함수를 적용해서 수행 시간 (elapsed time)을 비교해보니 dplyr의 distinct() 함수가 근소하게 빠르기는 합니다만, 차이가 그리 크지는 않네요. 


> a1 <- sample(1:99, 1000000000, replace=TRUE)

> system.time(unique(a1))

   user  system elapsed 

 13.676   7.327  22.999 

> system.time(!duplicated(a1))

   user  system elapsed 

 13.558   5.049  20.198 

> library(dplyr)

> system.time(dplyr::distinct(data.frame(a1)))

   user  system elapsed 

 17.602   1.645  19.267

 



많은 도움이 되었기를 바랍니다.

 

이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡' 단추를 꾸욱 눌러주세요.^^

 

 

728x90
반응형
Posted by Rfriend
,