본문 바로가기
R

[R] 데이터 시각화

by 빵으니 2020. 7. 8.
Chap04

시각화

여러 그래프로 데이터 나타내기

분석

  • 탐색적 자료분석(EDA, Exploratory Data Analysis)
  • 확증적 자료분석(CDA, Confirmatory Data Analysis)

탐색적 자료 분석

  • 빠르게 자료의 특징을 찾는 행위

확증적 자료 분석

  • 느리더라도 확실한 결론을 내리는 행위

자료의 현시성

  • 자료를 빠르게 그래프로 그리고 그래프를 통해 자료의 특징을 찾아내고 탐색하는 것

시각화

  • 시각화를 통해 데이터의 특징을 찾아내는데 효과적
  • 자료의 특징은 어떤 결론을 확증하는증거
  • Report

R에서 그래프를 그래는 이유

  • 빠르게 데이터를 탐색하기 위해(EDA) => plot()
  • 보다 정교한 데이터의 특징을 나타내기 위해 => ggplot2 패키지
  • Report용 => rChart 패키지

R에서 제공하는 기본 그래프

고수준 그래프 함수

  • 한번에 한 개만 실행되는 함수
  • plot(), barplot(), hist(), boxplot()

저수준 그래프 함수

  • 고수준 그래프를 꾸며주는 함수
  • 그래프 타이틀, X-Y 축 이름, 그래프 색 등

plot()

  • 변수의 형식에 따라 알아서 그래프를 그림 => generic 함수
  • 변수는 수치형이나 명목형 값이어야 함
In [1]:
# data load
df <- read.csv('R-ggagi-data/example_studentlist.csv')
str(df)
'data.frame':	17 obs. of  8 variables:
 $ name     : Factor w/ 17 levels "강수친","김길동",..: 2 12 17 6 10 7 1 14 13 9 ...
 $ sex      : Factor w/ 2 levels "남자","여자": 1 2 1 1 2 2 2 2 1 1 ...
 $ age      : int  23 22 24 23 20 21 22 23 23 22 ...
 $ grade    : int  3 2 4 3 1 2 1 1 3 2 ...
 $ absence  : Factor w/ 2 levels "무","유": 2 1 1 1 2 1 1 1 1 1 ...
 $ bloodtype: Factor w/ 4 levels "A","AB","B","O": 4 2 3 2 1 4 4 1 3 3 ...
 $ height   : num  165 170 175 182 168 ...
 $ weight   : num  68.2 53 80.1 85.7 49.5 52 45.3 55 64.2 61.3 ...
In [2]:
# 변수 1개
# 첫번째 행부터 마지막 행까지 산점도로 표시
plot(df$age)
In [3]:
# 변수 2개 : 상관관계
plot(df$height, df$weight)
In [4]:
# 변수 2개 : 상관관계 - 종속변수(y) ~ 독립변수(x)
plot(df$height ~ df$weight)
In [5]:
# 수치형 변수, 명목형 변수 (남자1, 여자2)
plot(df$height, df$sex)
In [6]:
# 명목형 변수, 수치형 변수 (남자1, 여자2)
plot(df$sex, df$height)
In [7]:
# 수치형 변수 ~ 명목형 변수 (남자1, 여자2)
plot(df$height ~ df$sex)
In [8]:
# 명목형 변수 ~ 수치형 변수 (남자1, 여자2)
plot(df$sex ~ df$height)
In [9]:
# 데이터 프레임 넣기
df2 <- data.frame(df$height, df$weight)
plot(df2)
In [12]:
# 데이터 프레임 넣기
# 데이터 프레임에서 변수가 늘어난다는 것은 차원 수가 늘어난다는 것!
df3 <- data.frame(df2, df$age)
plot(df3)
In [13]:
# 데이터 프레임 넣기
plot(df)

Level 별 그래프 보기

In [14]:
# 성별 별도 표시
plot(df$weight~df$height, pch=as.integer(df$sex))
In [15]:
# 성별 별도 표시 - 레전드(범례)추가
plot(df$weight~df$height, pch=as.integer(df$sex))
legend('topleft', c('man','woman'), pch=df$sex)

coplot() : 조건화 그래프

  • 명목형 변수를 보기 좋음
In [16]:
# 성별에 따른 키와 몸무게
coplot(df$weight ~ df$height | df$ sex)
In [21]:
# 저수준 그래프 함수
# 제목 달기 - ann = F 모든 라벨 삭제
plot(df$weight ~ df$height, ann=F)
title(main = '몸무게와 키의 상관관계 y=x')
title(ylab = '몸무게')
title(xlab = '키')

# 격자 추가
grid()
# vertical / horizon
abline(v=mean(df$height), h=mean(df$weight), col='red')

barplot() : 빈도수 그래프

In [22]:
blood_type <- table(df$bloodtype)
blood_type
 A AB  B  O 
 4  3  5  5 
In [23]:
barplot(blood_type)
title(main = '혈액형 빈도수')
title(xlab = '혈액형')
title(ylab = '빈도수')
In [24]:
# 그룹별 평균
height_blood <- tapply(df$height, df$bloodtype, mean)
height_blood
A
169.075
AB
177.4
B
171.28
O
165.14
In [30]:
barplot(height_blood, ylim=c(0,200)) # y limit : y의 범위 지정
In [32]:
# 빈도수는 plot() 바로 그릴 수 있음
# plot은 차트만 빨리 그릴 때 사용
plot(df$bloodtype)

boxplot()

In [33]:
boxplot(df$height)
In [35]:
# 혈액형별 키
boxplot(df$height ~ df$bloodtype)
In [38]:
subset(df, subset=(df$bloodtype=='O'))
namesexagegradeabsencebloodtypeheightweight
1김길동남자 23 3 O 165.3 68.2
6박미희여자 21 2 O 162.0 52.0
7강수친여자 22 1 O 155.2 45.3
11박수호남자 24 4 O 167.1 62.0
14이희진여자 23 3 O 176.1 53.1

hist()

  • x축은 반드시 수치형 연속형 변수
  • 계급을 정하고 계급의 도수를 그래프로 나타낸 것
  • x축이 연속형 변수- 계급(구간)- 확률밀도함수 vs 확률질량함수
  • 확률 1
  • 상대도수밀도 = 상대도수 / 계급
In [48]:
hist(df$height)
In [40]:
# 막대수 조정
hist(df$height, breaks=10)
In [47]:
# 상대도수 밀도 prob = T, 곡선추가 lines
# bar의 면적이 상대도수
hist(df$height, breaks = 10, prob = T)
lines(density(df$height))
In [49]:
# 계급 7간격 만들기
break_point <- seq(min(df$height), max(df$height)+7, by=7)
hist(df$height, breaks = break_point)
In [51]:
# 계급 수동 설정 -> 상대밀도함수(Density)로 바뀜
# 면적 = 확률
diff_point <- c(min(df$height), 165, 170, 180, 185)
hist(df$height, breaks = diff_point)

한 화면에 여러개 그래프 그리기

In [52]:
par(mfrow = c(2,3))
plot(df$weight, df$height)
plot(df$sex, df$height)
barplot(table(df$bloodtype))
boxplot(df$height)
boxplot(df$height ~ df$bloodtype)
hist(df$height, breaks = 10)
In [53]:
# 다시 1개씩 그리기
par(mfrow = c(1,1))

넘겨가며 그래프 보기

In [54]:
plot(df$weight~df$height + df$age + df$grade + df$absence + df$sex)

R 기본 그래프 겹쳐 나타내기

  • lines()를 이용해서 라인 그래프만 겹칠 수 있음
In [55]:
# 시계열 변수 임의로 만들기
runif(30) # 난수 발생
round(runif(30)*100) # 소수점 처리
TS1 <- c(round(runif(30)*100))
TS1
  1. 0.37740490725264
  2. 0.32731687091291
  3. 0.468677942641079
  4. 0.413320353254676
  5. 0.581772728823125
  6. 0.176928349072114
  7. 0.0811733154114336
  8. 0.30926424684003
  9. 0.189279138343409
  10. 0.571349890902638
  11. 0.914214281598106
  12. 0.690616220235825
  13. 0.502892157994211
  14. 0.295741136884317
  15. 0.0543842071201652
  16. 0.0688835715409368
  17. 0.592720918823034
  18. 0.115172864869237
  19. 0.20915288082324
  20. 0.908083542948589
  21. 0.487793480511755
  22. 0.339343579718843
  23. 0.0542152896523476
  24. 0.499258111929521
  25. 0.818614456569776
  26. 0.916900245705619
  27. 0.875328528694808
  28. 0.489335625665262
  29. 0.697072512470186
  30. 0.562604923965409
  1. 8
  2. 14
  3. 75
  4. 7
  5. 13
  6. 83
  7. 44
  8. 98
  9. 6
  10. 3
  11. 43
  12. 18
  13. 75
  14. 86
  15. 67
  16. 2
  17. 25
  18. 18
  19. 68
  20. 3
  21. 9
  22. 15
  23. 73
  24. 8
  25. 25
  26. 53
  27. 57
  28. 85
  29. 40
  30. 91
  1. 38
  2. 21
  3. 30
  4. 1
  5. 31
  6. 55
  7. 4
  8. 97
  9. 31
  10. 37
  11. 93
  12. 51
  13. 82
  14. 57
  15. 17
  16. 47
  17. 65
  18. 55
  19. 83
  20. 51
  21. 70
  22. 30
  23. 100
  24. 46
  25. 37
  26. 57
  27. 75
  28. 99
  29. 26
  30. 82
In [57]:
TS2 <- c(round(runif(30)*100))
TS2
  1. 66
  2. 61
  3. 44
  4. 75
  5. 52
  6. 9
  7. 86
  8. 52
  9. 23
  10. 73
  11. 66
  12. 37
  13. 18
  14. 21
  15. 93
  16. 49
  17. 3
  18. 79
  19. 49
  20. 13
  21. 17
  22. 74
  23. 12
  24. 28
  25. 91
  26. 6
  27. 55
  28. 95
  29. 84
  30. 21
In [58]:
# 자료 정렬 
TS1 <- sort(TS1, decreasing = F)
TS2 <- sort(TS2, decreasing = F)
TS1
TS2
  1. 1
  2. 4
  3. 17
  4. 21
  5. 26
  6. 30
  7. 30
  8. 31
  9. 31
  10. 37
  11. 37
  12. 38
  13. 46
  14. 47
  15. 51
  16. 51
  17. 55
  18. 55
  19. 57
  20. 57
  21. 65
  22. 70
  23. 75
  24. 82
  25. 82
  26. 83
  27. 93
  28. 97
  29. 99
  30. 100
  1. 3
  2. 6
  3. 9
  4. 12
  5. 13
  6. 17
  7. 18
  8. 21
  9. 21
  10. 23
  11. 28
  12. 37
  13. 44
  14. 49
  15. 49
  16. 52
  17. 52
  18. 55
  19. 61
  20. 66
  21. 66
  22. 73
  23. 74
  24. 75
  25. 79
  26. 84
  27. 86
  28. 91
  29. 93
  30. 95
In [60]:
plot(TS1, type='l')  # line
In [61]:
plot(TS1, type='l')
lines(TS2, lty='dashed', col='red')

dbinom() : 이항분포의 확률값

  • dbinom(x, size, prob)
  • x : 확률밀도함수값을 얻을 x 벡터
  • size : 이항분포 B(n,p)에서 n값을 설정
  • prob : 이항분포 B(n,p)에서 p값을 설정
  • 예) x가 이항분포 B(10, 0.2)일 경우, P[x=2]의 확률값은 dbinom(2,10,0.2)
  • 이항분포 : 연속된 n번의 독립적 시행에서 각 시행이 확률 p를 가질 때의 이산확률 분포 (베르누이 시행)
In [62]:
x1 <- seq(1,100,1)

# dbinom(v,n,p) B(n,p) 이항분포함수 값 만들기
y1 <- dbinom(x1,100,0.25) 
head(y1)
  1. 1.06906739512716e-11
  2. 1.76396120195982e-10
  3. 1.92075775324516e-09
  4. 1.55261251720649e-08
  5. 9.93672011012155e-08
  6. 5.2443800581197e-07
In [64]:
x2 <- seq(1,50,1)

# dbinom(v,n,p) B(n,p) 이항분포함수 값 만들기
y2 <- dbinom(x2,50,0.5)
head(y2)
  1. 4.44089209850066e-14
  2. 1.08801856413266e-12
  3. 1.74082970261225e-11
  4. 2.04547490056939e-10
  5. 1.88183690852383e-09
  6. 1.41137768139287e-08
In [66]:
plot(x1, y1, type = 'h', ylim = c(0,0.15), xlim=c(0,60))
lines(x2, y2, col='red')

정교한 시각화로 분석하기(ggplot2)

  • 객체에 담아 재사용 가능
  • plot() 같은 함수느 변수에 담아 재사용 불가
In [67]:
library('ggplot2')
library('ggthemes')
Warning message:
"package 'ggplot2' was built under R version 3.6.3"Warning message:
"package 'ggthemes' was built under R version 3.6.3"
In [68]:
g1 <- ggplot(data=diamonds, aes(x=carat, y=price, colour-clarity))
g2 <- geom_point()
g3 <- theme_wsj()
In [74]:
g1 + g2 + g3
In [75]:
# 테마만 바꾸기
g1 + g2 + theme_bw()

ggplot()

  • 데이터 x, y축, colour 등 그래프 요소에 매핑하는 일
  • 미적 요소 매핑(aesthetic mapping) -> aes()

geom()

  • 그래프 종류 선택
  • 기하객체(geometric object) 함수, 점이나 선을 기하객체라 함
In [86]:
# 데이터 로드
df <- read.csv('R-ggagi-data/example_studentlist.csv')
In [93]:
g1 <- ggplot(df, aes(x=height, y=weight, colour=bloodtype))
In [94]:
g1 + geom_point()
In [96]:
g1 + geom_line()
In [98]:
g1 + geom_point() + geom_line()
In [99]:
g1 + geom_line(aes(colour=sex)) + geom_point(size=10)

facet_grid() : 명목형 변수를 기준으로 별도 그래프 그리기

In [100]:
g1 + geom_point(size=10) + geom_line(size=1) + facet_grid(.~sex) # 성별 독립변수
In [102]:
g1 + geom_point(size=10) + geom_line(size=1) + facet_grid(sex~.) # 성별 종속 변수
In [104]:
# y축 범위(scale) 각각 맞게 처리
# 성별 종속변수
g1 + geom_point(size=5) + geom_line(size=1) + facet_grid(sex~., scale='free')
In [106]:
# y축 scale 적용 안 됨
# 성별 독립변수
g1 + geom_point(size=5) + geom_line(size=1) + facet_grid(.~sex, scale='free')
In [108]:
# y축 scale 적용
# 성별 독립변수
g1 + geom_point(size=5) + geom_line(size=1) + facet_wrap(~sex, scale='free')
In [109]:
# facet_grid() - 명목형 변수들의 level 별 그래프를 보여주는 목적
g <- ggplot(mpg, aes(displ, hwy)) # 배기량, 고속도로 연비 산점도
g + geom_point()
In [110]:
# 차량 종류에 따른 배기량, 고속도로 연비 보기
g + geom_point() + facet_grid(.~class)
In [111]:
# 종속변수 추가
g + geom_point(alpha=.3) + facet_grid(cyl ~ class, scale='free')
In [112]:
# 종속변수 추가 - 각각의 그래프를 모아서 보기 위함
g + geom_point(alpha=.3) + facet_wrap(cyl~class, scale='free')

geom_bar() : 바 그래프

In [113]:
ggplot(df, aes(x=bloodtype)) + geom_bar()
In [114]:
# Level 별 색 넣기 - fill
ggplot(df, aes(x=bloodtype, fill=sex)) + geom_bar()
In [115]:
# Level별 색 구분, 남녀 각각 표시 - position
ggplot(df, aes(x=bloodtype, fill=sex)) + geom_bar(position = 'dodge')
In [116]:
# Level별 색 구분, 남녀 각각 표시- position
# 누적 없이 겹치기
ggplot(df, aes(x=bloodtype, fill=sex)) + geom_bar(position = 'identity')
In [117]:
# Level별 색 구분, 남녀 각각 표시- position
# 비율로 표시
ggplot(df, aes(x=bloodtype, fill=sex)) + geom_bar(position='fill')
In [118]:
# 막대 넓이 바꾸기 - width
ggplot(df, aes(x=bloodtype, fill=sex)) + geom_bar(position='dodge', width = 0.5)
In [119]:
# 도수 값 말고, 계산된 값 사용하기 - 혈액형별 키 평균
height_mean <- tapply(df$height, df$bloodtype, mean)
height_mean
A
169.075
AB
177.4
B
171.28
O
165.14
In [130]:
# 변수명 주기
df2 <- data.frame(height_mean)
df2$bloodtype  <- rownames(df2)
rownames(df2) <- NULL  # 불필요한 rownames 삭제
In [131]:
df2
height_meanbloodtype
169.075A
177.400AB
171.280B
165.140O
In [134]:
# stat = 'identity' 값 그대로, 생략시 stat= 'bin' 빈도수 표시
ggplot(df2, aes(x=bloodtype, y=height_mean, fill=bloodtype)) + 
geom_bar(stat = 'identity') + 
scale_fill_brewer(palette='Oranges')

히스토그램 : geom_histogram()

  • 연속형 변수 사용
In [135]:
g1 <- ggplot(diamonds, aes(x=carat))
In [136]:
# y축 계급 빈도수
g1 + geom_histogram(binwidth = 0.1, fill='orange')
In [138]:
# 예약어 - ..ncount.. 표준화 된 도수
# y = .. ncount ..는 막대 1.0이 가장 높은 히스토그램을 제공하고 나머지는 그에 맞게 조정됨
g1 + geom_histogram(aes(y=..count..), binwidth = 0.1, fill='blue')
In [140]:
# 예약어 - ..density.. 밀도
g1 + geom_histogram(aes(y=..density..), binwidth=0.1, fill='red')
In [141]:
# 예약어 - ..ndensity.. 표준화된 밀도
g1 + geom_histogram(aes(y=..ndensity..), binwidth=0.1, fill=' orange')
In [142]:
# 그룹별로 그리기 - facet_grid
g1 + geom_histogram(binwidth = 0.1, fill='orange') + 
facet_grid(color~.) # color변수 level 별로
In [143]:
# 그룹별로 그리기 - 축 변경 facet_grid - scales='free'
g1 + geom_histogram(binwidth = 0.1, fill='blue') + 
facet_grid(color~., scales='free') # color변수 level별로
In [144]:
# level 별로 겹쳐 보이기
g1 + geom_histogram(aes(fill=color), binwidth = 0.1, alpha=0.5)

산점도 그리기 : geom_point()

In [145]:
# 데이터 로드
df <- read.csv('R-ggagi-data/example_studentlist.csv')
head(df)
namesexagegradeabsencebloodtypeheightweight
김길동남자 23 3 O 165.3 68.2
이미린여자 22 2 AB 170.1 53.0
홍길동남자 24 4 B 175.0 80.1
김철수남자 23 3 AB 182.1 85.7
손세수여자 20 1 A 168.0 49.5
박미희여자 21 2 O 162.0 52.0
In [147]:
g1 <- ggplot(df, aes(x=weight, y=height))
In [148]:
g1 + geom_point()
In [149]:
# level별 색상 주기
g1 + geom_point(aes(colour=sex), size=7)
In [150]:
# 점 모양 바꾸기 1
g1 + geom_point(aes(colour=sex, shape=sex), size=7)
In [151]:
# 점 모양 바꾸기2
g1 + geom_point(aes(colour=sex, shape=bloodtype), size=7)
In [152]:
# colour에 연속형 변수 넣기 (그라데이션)
g1 + geom_point(aes(colour=height, shape=sex), size=7)
In [154]:
# size에 연속형 변수 넣기
g1 + geom_point(aes(size=height, shape=sex), colour='orange')
In [155]:
# 산점도로 회귀분석 그리기
g1 + geom_point(aes(colour=sex), size=7) + 
geom_smooth(method = 'lm') # lm은 회귀에서 쓰는 함수
`geom_smooth()` using formula 'y ~ x'
In [156]:
# 점마다 이름 넣기 - geom_text()
g1 + geom_point(aes(colour=sex), size=7) + 
geom_text(aes(label=name))
In [157]:
# 점마다 이름 넣기 - 위치 조절 vjust, 글자색 colour
g1 + geom_point(aes(colour=sex), size=7) + 
geom_text(aes(label=name), vjust=-1.5, colour='grey35')

theme() : 만들어져있는 테마 사용

  • theme_wsj() : 월스트리트저널에서 많이 사용하는 그래프 스타일
In [ ]:

'R' 카테고리의 다른 글

[R] R 필수 패키지 설치 및 기초  (0) 2020.07.08
[R] 데이터 시각화 및 EDA  (0) 2020.07.08
[R] 기술통계 - 실전예제  (0) 2020.07.08
[R] 기술통계  (0) 2020.07.08
[R] 데이터 개념 이해하기 (2-2)  (0) 2020.07.08

댓글