Radar Chart
Keon-Woong Moon
May 20, 2016
Radar Chart의 구현
Radar chart 는 세개 이상의 정량적인 변수를 2차원으로 표현하는 그래프이다. 예를 들어 1974년 Motor trend US잡지에 실린 자동차 32종을 수동과 자동 변속기를 구분하여 다음과 같은 그래프를 그려보고자 한다.
붓꽃(iris)의 세가지 종에 따른 꽃잎과 꽃받침의 길이, 넓이를 비교해 보면 다음과 같다.
또 다른 예로 저자가 만든 moonBook 패키지에 있는 acs환자의 데이타를 남여로 구분해 보면 다음과 같다.
그림에서 보는 바와 같이 여자환자의 발병연령이 높고 키와 몸무게는 남자가 크고 몸무게가 많이 나가지만 체질량지수나 혈중콜레스테롤 등은 동일한 것을 한 눈에 알 수 있다.
자료의 전처리
이와 같은 그래프를 그리려면 (1) 먼저 자료를 long form으로 정리해야 하며 (2) 각 군별로 자료의 평균을 구하고 (3) 이 자료를 이용하여 그림을 그려야 한다.
가상의 자료 만들기
먼저 한 고등학교에서 문과학생 100명과 이과학생 100명을 대상으로 영어, 수학, 역사, 과학 시험을 보았다고 하자. 편의상 문과 학생(B)의 영어, 역사 시험 성적이 이과학생에 비해 조금 높은 것으로 가정하고 이과학생(A)의 수학, 과학 성적이 문과 학생에 비해 조금 높은 것으로 가정하고 가상의 자료를 만들어 보았다.
English1=sample(50:90,100,replace=TRUE)
Math1=sample(seq(2.5,5,by=0.1),100,replace=TRUE)
History1=sample(60:80,100,replace=TRUE)
Science1=sample(seq(3,4.5,by=0.1),100,replace=TRUE)
English2=sample(55:95,100,replace=TRUE)
Math2=sample(seq(1.5,4.5,by=0.1),100,replace=TRUE)
History2=sample(70:95,100,replace=TRUE)
Science2=sample(seq(2.5,4,by=0.1),100,replace=TRUE)
Class=c(rep("A",100),rep("B",100))
English=c(English1,English2)
Math=c(Math1,Math2)
History=c(History1,History2)
Science=c(Science1,Science2)
data1=data.frame(English,Math,History,Science,Class)
head(data1)
English Math History Science Class
1 68 4.6 64 4.0 A
2 52 2.9 61 4.5 A
3 53 3.2 64 3.7 A
4 87 3.6 80 4.2 A
5 73 4.6 79 3.1 A
6 51 3.2 63 4.1 A
summary(data1)
English Math History Science Class
Min. :50.00 Min. :1.500 Min. :60.00 Min. :2.500 A:100
1st Qu.:62.00 1st Qu.:2.700 1st Qu.:70.00 1st Qu.:3.100 B:100
Median :72.00 Median :3.500 Median :74.50 Median :3.500
Mean :72.55 Mean :3.455 Mean :76.03 Mean :3.514
3rd Qu.:82.00 3rd Qu.:4.125 3rd Qu.:82.00 3rd Qu.:3.900
Max. :95.00 Max. :5.000 Max. :95.00 Max. :4.500
자료가 잘 만들어져 있는지 A반과 B반의 성적 평균을 보려면 다음과 같이 한다.
aggregate(.~Class,data1,mean)
Class English Math History Science
1 A 70.5 3.837 69.97 3.763
2 B 74.6 3.073 82.09 3.266
넓은 형태를 긴 형태로
이 자료는 넓은 형태(wide form)의 자료이다. 이 자료를 이용하여 그림을 그리려면 먼저 자료를 긴 형태(long form)로 바꾸어 주어야 한다. reshape2 패키지의 melt() 함수를 써서 자료의 형태를 바꿀 수 있다.
longdf=melt(data1,id.vars="Class")
head(longdf)
Class variable value
1 A English 68
2 A English 52
3 A English 53
4 A English 87
5 A English 73
6 A English 51
반별, 과목별 평균 구하기
이제 이 자료를 각 과목별로 평균을 내보자. plyr패키지의 ddply()함수를 이용하였다.
df=ddply(longdf,.(Class,variable),summarize,mean(value))
colnames(df)[length(df)]="value"
df
Class variable value
1 A English 70.500
2 A Math 3.837
3 A History 69.970
4 A Science 3.763
5 B English 74.600
6 B Math 3.073
7 B History 82.090
8 B Science 3.266
그래프 그리기
이 자료를 이용하여 점과 선그래프를 그리면 다음과 같다.
ggplot(data=df,aes(x=variable,y=value,group=Class,colour=Class))+
geom_point()+geom_line()
geom_polygon을 이용하여 그림을 그리고 coord_polar()를 사용하여 원형그래프로 바꾼다.
ggplot(data=df,aes(x=variable,y=value,group=Class,colour=Class,fill=Class))+
geom_point()+geom_polygon(alpha=0.4)+coord_polar()
여기서 문제가 발생한다. 영어와 역사는 100점 만점으로 채점이 되어 있고 수학과 과학은 5.0 만점으로 채점이 되어 있어 그래프르르 그리게 되면 수학, 과학은 영어, 역사에 비해 값이 적으므로 차이가 나지 않는 것 처럼 보인다. 이를 해결하기 위해 전체 자료를 rescale 해서 최저값 0, 최고값을 1로 바꾼후 그래프를 그리면 좋을 것이다. 이 용도로 scales패키지의 rescale()함수를 사용하면 된다. 다음의 rescaledf() 함수는 데이타 프레임 중 숫자형인 것만 골라 rescale해준다.
rescale_df=function(data,groupvar=NULL){
if(is.null(groupvar)) df=data
else df=data[,-which(names(data) %in% groupvar)]
select=sapply(df,is.numeric)
df[select]=lapply(df[select], scales::rescale)
if(!is.null(groupvar)) {
df=cbind(df,data[[groupvar]])
colnames(df)[length(df)]=groupvar
}
df
}
rescaled=rescale_df(data1)
head(rescaled)
English Math History Science Class
1 0.40000000 0.8857143 0.11428571 0.75 A
2 0.04444444 0.4000000 0.02857143 1.00 A
3 0.06666667 0.4857143 0.11428571 0.60 A
4 0.82222222 0.6000000 0.57142857 0.85 A
5 0.51111111 0.8857143 0.54285714 0.30 A
6 0.02222222 0.4857143 0.08571429 0.80 A
이 데이타 프레임을 이용하여 긴 형태로 바꾸고 다시 각 반과 과목별로 평균을 냐보면 다음과 같다.
longdf2=melt(rescaled,id.vars="Class")
head(longdf2)
Class variable value
1 A English 0.40000000
2 A English 0.04444444
3 A English 0.06666667
4 A English 0.82222222
5 A English 0.51111111
6 A English 0.02222222
df2=ddply(longdf2,.(Class,variable),summarize,mean(value))
colnames(df2)[length(df2)]="value"
df2
Class variable value
1 A English 0.4555556
2 A Math 0.6677143
3 A History 0.2848571
4 A Science 0.6315000
5 B English 0.5466667
6 B Math 0.4494286
7 B History 0.6311429
8 B Science 0.3830000
geom_polygon을 이용하여 그림을 그리고 coord_polar()를 사용하여 원형그래프로 바꾼다.
ggplot(data=df2,aes(x=variable,y=value,group=Class,colour=Class,fill=Class))+
geom_point()+geom_polygon(alpha=0.4)+coord_polar()
새로운 좌표계의 정의
Radial chart는 직선으로 그래프가 그려지나 geom_polygon()은 coord_polar()로 변형할 경우 원호로 그려진다. 원형좌표계에서 직선으로 polygon을 그리는 새로운 좌표계를 하나 만든다.
coord_radar <- function (theta = "x", start = 0, direction = 1)
{
theta <- match.arg(theta, c("x", "y"))
r <- if (theta == "x")
"y"
else "x"
ggproto("CoordRadar", CoordPolar, theta = theta, r = r, start = start,
direction = sign(direction),
is_linear = function(coord) TRUE)
}
이제 이 좌표계를 적용하여 그래프를 그린다.
ggplot(data=df2,aes(x=variable,y=value,group=Class,colour=Class,fill=Class))+
geom_point()+geom_polygon(alpha=0.4)+coord_radar()
y축 범위의 재설정
y축의 범위가 0.3부터 0.6까지로 되어 있어 그래프가 왜곡되어 보인다. y축 범위를 0부터 1까지 설정한다.
ggplot(data=df2,aes(x=variable,y=value,group=Class,colour=Class,fill=Class))+
geom_point()+geom_polygon(alpha=0.4)+coord_radar()+ylim(0,1)+
theme(legend.position="bottom")+xlab("")+ylab("")
이 그래프를 보면 문과학생의 영어, 역사 점수가 높고 이과 학생의 수학 과학 점수가 높은 것을 한눈에 알수 있다.
ggRadar()함수의 구현
이상의 과정을 한꺼번에 해주는 함수를 만들어 사용하면 편리할 것이다. 저자가 만든 ggRadar()함수는 wide form의 데이타를 내부적으로 long form으로 바꾸어주고 group변수를 정해주는 경우 그룹별로 평균을 구해 그래프를 그려준다. autorescale인수를 TRUE로 주는 경우 rescale도 해준다.
ggRadar(data=mtcars,groupvar="am",autorescale = TRUE)
ggRadar(data=mtcars,groupvar="cyl",autorescale = TRUE)
다음과 같이 사용할 수도 있습니다.
mtcars$model=rownames(mtcars)
ggRadar(mtcars[1:9,],autorescale=TRUE,groupvar="model",legend.position="none")+
ylim(0,1)+facet_wrap(~model)
ggRadar()함수의 소스는 web-R.org의 게시판에 공개되어 있습니다.
Comment 0
- Total
- 의학논문 작성을 위한 R통계와 그래프
- R을 이용한 조건부과정분석
- 웹에서 클릭만으로 하는 R통계분석
- Learn ggplot2 Using Shiny App
- 일반화가법모형 소개
- 밑바닥부터 시작하는 ROC 커브 분석
- 웹R을 이용한 통계분석
- 의료인을 위한 R 생존분석
No. | Subject | Author | Date |
---|---|---|---|
25 | 2판 출판 예정일 문의 [2] | pslee | 2024.01.23 |
24 | 2판 혹시 언제쯤 출간 예정일지요? [1] | 니콜라오 | 2023.10.13 |
23 | 2판 [1] | rlagurrn | 2023.01.27 |
22 | mytable 문의 [2] | 떠도는고라니 | 2022.12.20 |
21 | 제2판 출간소식을 기다립니다.. [1] | swpapa | 2021.04.05 |
20 | 책 구매 하려고 하는데 품절이 되서 구매할수 있는지 궁금합니다. [1] | 기드온 | 2020.07.30 |
19 | 메타분석 강의록 | cardiomoon | 2020.05.31 |
18 | 설문조사데이터 | cardiomoon | 2020.05.08 |
17 | 데이터 전처리 예제 | cardiomoon | 2020.05.08 |
16 | moonbook package 설치에 문제가 있는 건가요? [2] | KCRS_LeeJM | 2017.03.14 |
15 | 해결되지 않는 레이텍, ztable, moonbook2에 대해 질문 드립니다. [1] | neurojang | 2017.01.04 |
14 | Interactive plot with ggplot2 and ggiraph [1] | cardiomoon | 2016.05.25 |
13 | ggBidirectionalBar.R | cardiomoon | 2016.05.22 |
12 | 인구피라미드 : Bidirectional Barplot | cardiomoon | 2016.05.22 |
» | Radar Chart | cardiomoon | 2016.05.20 |
10 | ggRadar.R | cardiomoon | 2016.05.20 |
9 | Rose plot with ggplot2 [1] | cardiomoon | 2016.05.10 |
8 | Pie plot과 Donut plot의 결합 [2] | cardiomoon | 2016.05.08 |
7 | 책에 있는 R code 만 추출한 R 파일입니다. [1] | cardiomoon | 2016.05.03 |
6 | 교재 예제자료 [2] | 통계마술사 | 2016.01.18 |