01. 기본 시각화
-01 plot
-02 barplot
-03 이상치 탐색
-04 히스토그램
-05 커널밀도함수
-06 파이차트
01. 기본 시각화
-01 plot
- 선그래프, 산점도
- 데이터프레임의 교차 산점도
- 모델 시각화
-02 barplot
- 범주형 데이터의 비교 시각화(y축: 수치형, x축: 범주형)
barplot(height, # 데이터
width = 1, # 막대 너비
space = NULL, # 막대 공간
names.arg = NULL, # 막대 이름
legend.text = NULL, # 범례
beside = FALSE, # 서로 다른 막대로의 출력 여부
horiz = FALSE, # 수평 여부
density = NULL, # 빗금 밀도
angle = 45, # 빗금 각도
border = par("fg"), # 테두리
... )
# 예) 여러 막대그래프 출력(벡터)
barplot(c(15,60,3,80,100), col = rainbow(5),
names.arg = c('A','B','C','D','E'),
density = 30, angle = 130, horiz = T)

# 예) 여러 막대그래프 출력(2차원)
library(googleVis)
df1 <- dcast(Fruits, Year ~ Fruit, value.var = 'Sales')
> dcast(Fruits, Year ~ Fruit, value.var = 'Sales')
Year Apples Bananas Oranges
1 2008 98 85 96
2 2009 111 94 93
3 2010 89 81 98
barplot(df1)
> barplot(df1)
barplot.default(df1)에서 다음과 같은 에러가 발생했습니다:
'height'는 반드시 벡터 또는 행렬이어야 합니다
df1$Year <- NULL
barplot(as.matrix(df1))

barplot(as.matrix(df1), beside = T, col = rainbow(3))

barplot(as.matrix(df1), beside = T, col = rainbow(3),
ylim = c(0, 150),
cex.axis = 1.5, cex.names = 1.5,
xlab = 'Fruits', cex.lab = 2, col.lab = 'red')
legend('topright', inset = c(0.03, 0),
legend = rownames(df1), fill = rainbow(3), horiz = T,
title = '연도')

# [ 연습문제 - barplot 시각화 ]
movie <- read.csv('영화이용현황.csv', fileEncoding = 'cp949')
head(movie)
# 요일별, 연령별 / 이용비율은 총합으로
# 연령은 n0대, 60대 이상은 60대로
# legend는 2x3
[내 답안]
str(movie)
unique(movie$연령대)
# 연령대 정리
movie$연령대 <- str_replace_all(movie$연령대, '\\d$|\\d대 이상', '0대')
movie$연령대 <- str_replace_all(movie$연령대, '70대', '60대')
# 요일 계산
movie$date1 <- str_c(movie$년,movie$월,movie$일, sep = '-')
movie$date1 <- as.Date(movie$date1, '%Y-%m-%d')
movie$day1 <- strftime(movie$date1, '%a')
unique(movie$day1)
# 요일 정렬
movie$day2 <- movie$day1
movie$day2 <- str_replace(movie$day2,'월','1')
movie$day2 <- str_replace(movie$day2,'화','2')
movie$day2 <- str_replace(movie$day2,'수','3')
movie$day2 <- str_replace(movie$day2,'목','4')
movie$day2 <- str_replace(movie$day2,'금','5')
movie$day2 <- str_replace(movie$day2,'토','6')
movie$day2 <- str_replace(movie$day2,'일','7')
unique(movie$day2)
# 필요한 데이터만 추출
movie2 <- ddply(movie, .(day1, day2, 연령대), summarise, 총이용률 = sum(이용_비율...))
movie3 <- arrange(dcast(movie2, 연령대 ~ day1 + day2 ), day2)
movie4 <- dcast(movie2, 연령대 ~ day2)
head(movie4)
# 요일 라벨링
names(movie4) <- str_replace_all(names(movie4), '1', '월')
names(movie4) <- str_replace_all(names(movie4), '2', '화')
names(movie4) <- str_replace_all(names(movie4), '3', '수')
names(movie4) <- str_replace_all(names(movie4), '4', '목')
names(movie4) <- str_replace_all(names(movie4), '5', '금')
names(movie4) <- str_replace_all(names(movie4), '6', '토')
names(movie4) <- str_replace_all(names(movie4), '7', '일')
ㅡ
# 시각화
my_col3 <- c('#F8F4CB','#FAF34E','#AFFA5A', '#77FA95', '#39FACD', '#5E92FA')
barplot(as.matrix(movie4[2:8]), beside = T, col = my_col3,
ylim = c(0, 15), xlab = '요일',
cex.axis = 1.3, cex.names = 1.3, cex.lab = 1.3)
legend("topright",
inset = c(0.03, 0.03),
legend = unique(movie4$연령대),
fill = my_col3, ncol = 2, title = '연령대')
title('요일별 연령대별 총 이용률 비교', cex.main = 1.5)
mtext('총이용률', side = 2, las = 1, at = 16)
box()

[문제풀이]
# 기초 데이터 생성
# 1) 연령대 가공
library(stringr)
v1 <- str_c(str_sub(movie$연령대, 1,1), '0대')
movie$연령대 <- str_replace(v1, '60대|70대', '60대 이상')
# 2) 요일
movie$요일 <- str_c(movie$년, movie$월, movie$일, sep = '/') |> as.Date() |> strftime('%A')
# 3) wide data 생성
library(reshape2)
total <- dcast(movie, 연령대 ~ 요일, sum, value.var = '이용_비율...')
rownames(total) <- total$연령대
total$연령대 <- NULL
# 4) 컬럼 재배치
total[,c(4,7,3,2,1,6,5)]
# 시각화
windowsFonts(
han = windowsFont("서울한강체 B")
)
par(family = 'han')
library(colorspace)
p1 <- sequential_hcl(6, 'ag_Sunset')
dev.new()
par(bg = '#F8F9F8')
par(family = 'han')
par('mar' = c(6,5,5,3))
barplot(as.matrix(total), beside = T, col = p1, las = 1, ylim = c(0,9),
main = '요일별 연령대별 영화 이용비율 비교', cex.main = 2.5,
xlab = '요일', cex.lab = 1.5)
mtext('이용비율(%)', side = 2, at = 8.5, las = 1, cex = 1.2)
legend('topright', inset = c(0.03, 0.08), ncol = 3, bg = '#EFE8E8',
legend = rownames(total), fill = p1, cex = 0.7,
title = '연령대', title.cex = 1, title.col = 'red')

-03 이상치 탐색
1. 사용자 정의
2. 기법
1) IQR(범위) : Q3 - Q1
Range : 최대 - 최소
3. 상자그림
- 수치형 데이터의 분포 비교 시각화
- IQR 기준으로 이상치 출력
- 최대, 최소, 이상치, Q3, Q1, IQR, median(Q2) 확인 가능
boxplot(iris[,-5])

boxplot(iris[,-5], col = p1[1:4], las = 1,
main = 'Box Plot', cex.main = 2,
xlab = 'Species', cex.lab = 1.5,
cex.axis = 0.8)

# 이상치 확인
summary(iris[,-5])
q1 <- quantile(iris$Sepal.Width)[2]
q3 <- quantile(iris$Sepal.Width)[4]
viqr <- q3 - q1
r1 <- iris[iris$Sepal.Width > q3 + 1.5*viqr, ]
r2 <- iris[iris$Sepal.Width < q1 - 1.5*viqr, ]
outlier <- rbind(r1, r2)
> outlier
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
16 5.7 4.4 1.5 0.4 setosa
33 5.2 4.1 1.5 0.1 setosa
34 5.5 4.2 1.4 0.2 setosa
61 5.0 2.0 3.5 1.0 versicolor
# 이상치 번호 출력
text(2.1, outlier$Sepal.Width, rownames(outlier), cex = 0.7)

-04 히스토그램
- 도수분포표를 시각화한 그림
- 수치형 데이터에 대한 분포 확인 시각화(계급별로 막대로 표현)
hist(x, # 데이터(벡터)
breaks, # 계급구간
freq = T, # y축 좌표 -> 도수
probability = F, # y축 좌표 -> 확률
include.lowest = TRUE, # 최솟값을 첫번째 계급 포함 여부
right = T # 오른쪽 닫힘 여부(a 초과 b 이하)
)
# 도수분포표
# 140 ~ 150 => 140이상 150미만 [140, 150) : left closed or 140초과 150이하(140, 150] : right closed
# 150 ~ 160
# 160 ~ 170
# ......
vheight <- c(140, 142, 150, 155, 158, 162, 168, 169, 170, 171, 177, 176, 177, 183)
hist(vheight)

hist(vheight, seq(130, 200, 10), probability = T)

-05 커널밀도함수
install.packages('ks')
library(ks)
# 화면분할
par(mfrow = c(1,2))
hist(vheight, seq(130, 200, 10), probability = T)
plot(kde(vheight))

-06 파이차트
- 범주형 자료의 수치를 비교하기 위한 시각화 기법
pie(x, # 데이터(벡터)
labels = names(x), # 각 파이 이름
edges = 200, # 경계선의 부드러움의 정도
radius = 0.8, # 반지름
clockwise = FALSE, # 데이터의 출력 방향(시계방향 여부)
init.angle = if(clockwise)
# 예) 기본 파이차트 그리기
v1 <- c(80, 20, 60, 40)
pie(v1,c('A','B','C','D'), col = rainbow(4), clockwise = T,
radius = 0.6, main = 'Pie Chart')
legend('topright', c('A','B','C','D'), fill = rainbow(4))

-07 3D 파이차트
install.packages('plotrix')
library(plotrix)
pie3D(x,
radius = 1,
height = 0.1,# 파이높이
start = 0,
labels = ,
labelcol = ,
labelpos = ,
labelcex = ,
explode = ) # 파이간격
pie3D(v1, labels = c('A','B','C','D'), col = p1[1:4],
radius = 1, main = 'Pie Chart', explode = 0.1)

# [ 연습문제 - 파이차트 시각화 ]
# delivery.csv 파일을 사용하여
# 업종별 통화건수의 총 비율을 파이차트로 시각화
deli <- read.csv('delivery.csv', fileEncoding = 'cp949')
> head(deli)
일자 시간대 업종 시도 시군구 읍면동
1 20180201 0 음식점-족발/보쌈전문 서울특별시 강남구 논현동
2 20180201 0 음식점-족발/보쌈전문 서울특별시 강남구 역삼동
3 20180201 0 음식점-족발/보쌈전문 서울특별시 강서구 내발산동
4 20180201 0 음식점-족발/보쌈전문 서울특별시 강서구 화곡동
5 20180201 0 음식점-족발/보쌈전문 서울특별시 동작구 신대방동
6 20180201 0 음식점-족발/보쌈전문 서울특별시 노원구 상계동
통화건수
1 5
2 5
3 5
4 5
5 5
6 5
# 기초 데이터 생성
library(plyr)
deli2 <- ddply(deli, .(업종), summarise, 총통화건수 = sum(통화건수))
total <- deli2$총통화건수
names(total) <- str_remove(deli2$업종, '음식점-')
vnames <- str_c(round(total/sum(total) * 100, 2), '%')
> head(total)
족발/보쌈전문 중국음식 치킨 피자
92191 438453 474925 176367
# 시각화
dev.new()
pie3D(total, col = p1[1:4], explode = 0.1,
main = '업종별 배달현황', cex.main = 2,
labels = vnames, labelcex = 1.2)
legend('topright', names(total), fill = p1[1:4], cex = 0.9,
title = '업종', title.col = 'red')

'아이티윌_데이터 분석 55기 > 강의내용 필기_통계 및 분석' 카테고리의 다른 글
| #1 1일차_통계 기초, 표본추출, 측정과 척도, 기초 통계량, 확률분포 (0) | 2026.04.13 |
|---|---|
| #10 10일차_ggplot2 (0) | 2026.04.13 |
| #8 8일차_dplyr, 시각화 (0) | 2026.04.09 |
| #7 7일차_데이터 형태 변환, NA 처리 (0) | 2026.04.08 |
| #6 6일차 : 외부파일 입출력, DB Connection, 기타 기능 (0) | 2026.04.07 |