군집화
- 주어진 대상 데이터들을 유사성이 높은 것끼리 묶어주는 기술
- 이 묶음을 군집, 범주, 그룹 등의 용어로 부름
- 비지도학습
분류
- 그룹의 형태로 알려진 데이터들이 있을 때 그룹을 모르는 어떤 데이터에 대해 어느 그룹에 속하는지를 예측하는 기술
- 지도학습
k-평균 군집화 알고리즘
- 사용하기 위해서는 군집의 개수(k)를 정해야 함
- 데이터의 군집이 몇 개 존재할지 사전에 정할 수 있는 경우가 있고 어려운 경우가 있음
단계 (k=2)
- 대상 데이터셋 준비
- 산점도 상에 임의의 점 2개를 만듦 (이 점은 각 군집의 중심점이 됨)
- 산점도 상의 점들 하나하나와 임의의 점 2개와의 거리를 계산하여 두 점 중 가까운 쪽으로 군집을 형성
- 두 개의 군집에서 중심점을 다시 계산하고 기존의 두 점의 위치를 새로 계산한 중심점 위치로 이동
- 4단계의 과정 반복
- 두 점의 위치가 더 이상 변동되지 않으면 군집의 중심점에 도달한 것으로 반복을 중단
- 마지막으로 각 점들은 두 점 중 가까운 군집으로 표시하고 군집화 종료
mydata <- iris[,1:4] # 데이터 준비
fit <- kmeans(x=mydata, centers=3)
fit
fit$cluster # 각 데이터에 대한 군집 번호
fit$centers # 각 군집의 중심점 좌표표
# 차원 축소 후 군집 시각화
library(cluster)
clusplot(mydata, fit$cluster, color=T, shade=T,
labels=2, lines=0)
# 데이터에서 두 번째 군집의 데이터만 추출
subset(mydata, fit$cluster==2)
> mydata <- iris[,1:4] # 데이터 준비
> fit <- kmeans(x=mydata, centers=3)
> fit
K-means clustering with 3 clusters of sizes 62, 50, 38
Cluster means:
Sepal.Length Sepal.Width Petal.Length Petal.Width
1 5.901613 2.748387 4.393548 1.433871
2 5.006000 3.428000 1.462000 0.246000
3 6.850000 3.073684 5.742105 2.071053
Clustering vector:
[1] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1
[52] 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1
[103] 3 3 3 3 1 3 3 3 3 3 3 1 1 3 3 3 3 1 3 1 3 1 3 3 1 1 3 3 3 3 3 1 3 3 3 3 1 3 3 3 1 3 3 3 1 3 3 1
Within cluster sum of squares by cluster:
[1] 39.82097 15.15100 23.87947
(between_SS / total_SS = 88.4 %)
Available components:
[1] "cluster" "centers" "totss" "withinss" "tot.withinss" "betweenss" "size"
[8] "iter" "ifault"
> fit$cluster # 각 데이터에 대한 군집 번호
[1] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1
[52] 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1
[103] 3 3 3 3 1 3 3 3 3 3 3 1 1 3 3 3 3 1 3 1 3 1 3 3 1 1 3 3 3 3 3 1 3 3 3 3 1 3 3 3 1 3 3 3 1 3 3 1
> fit$centers # 각 군집의 중심점 좌표표
Sepal.Length Sepal.Width Petal.Length Petal.Width
1 5.901613 2.748387 4.393548 1.433871
2 5.006000 3.428000 1.462000 0.246000
3 6.850000 3.073684 5.742105 2.071053
> # 차원 축소 후 군집 시각화
> library(cluster)
> clusplot(mydata, fit$cluster, color=T, shade=T,
+ labels=2, lines=0)
> # 데이터에서 두 번째 군집의 데이터만 추출
> subset(mydata, fit$cluster==2)
Sepal.Length Sepal.Width Petal.Length Petal.Width
1 5.1 3.5 1.4 0.2
2 4.9 3.0 1.4 0.2
3 4.7 3.2 1.3 0.2
4 4.6 3.1 1.5 0.2
5 5.0 3.6 1.4 0.2
6 5.4 3.9 1.7 0.4
7 4.6 3.4 1.4 0.3
8 5.0 3.4 1.5 0.2
9 4.4 2.9 1.4 0.2
10 4.9 3.1 1.5 0.1
11 5.4 3.7 1.5 0.2
12 4.8 3.4 1.6 0.2
13 4.8 3.0 1.4 0.1
14 4.3 3.0 1.1 0.1
15 5.8 4.0 1.2 0.2
16 5.7 4.4 1.5 0.4
17 5.4 3.9 1.3 0.4
18 5.1 3.5 1.4 0.3
19 5.7 3.8 1.7 0.3
20 5.1 3.8 1.5 0.3
21 5.4 3.4 1.7 0.2
22 5.1 3.7 1.5 0.4
23 4.6 3.6 1.0 0.2
24 5.1 3.3 1.7 0.5
25 4.8 3.4 1.9 0.2
26 5.0 3.0 1.6 0.2
27 5.0 3.4 1.6 0.4
28 5.2 3.5 1.5 0.2
29 5.2 3.4 1.4 0.2
30 4.7 3.2 1.6 0.2
31 4.8 3.1 1.6 0.2
32 5.4 3.4 1.5 0.4
33 5.2 4.1 1.5 0.1
34 5.5 4.2 1.4 0.2
35 4.9 3.1 1.5 0.2
36 5.0 3.2 1.2 0.2
37 5.5 3.5 1.3 0.2
38 4.9 3.6 1.4 0.1
39 4.4 3.0 1.3 0.2
40 5.1 3.4 1.5 0.2
41 5.0 3.5 1.3 0.3
42 4.5 2.3 1.3 0.3
43 4.4 3.2 1.3 0.2
44 5.0 3.5 1.6 0.6
45 5.1 3.8 1.9 0.4
46 4.8 3.0 1.4 0.3
47 5.1 3.8 1.6 0.2
48 4.6 3.2 1.4 0.2
49 5.3 3.7 1.5 0.2
50 5.0 3.3 1.4 0.2
kmeans()
centers
는 군집의 개수를 전달
fit
K-means clustering with ~
부분은 각 군집에 속한 데이터들의 개수 정보Cluster means
부분은 각 군집의 중심점 좌표값Clustering vector
부분은 각 데이터에 대한 군집 번호
clusplot()
fit$cluster
는 군집화 결과에서 관측값별 군집 번호labels
는 군집화 대상 데이터셋에서 개별 관측값을 그래프상에 어떻게 나타낼지를 지정(1이면 기호, 2면 숫자)lines
는 군집의 중심점과 중심점을 연결하는 선을 표시할지 여부를 결정(0은 표시x, 1은 표시)
k-평균 군집화에서 고려할 점
- 모든 변수가 동등한 영향을 갖도록 하기 위해 모든 변수의 자료 범위를 0~1 사이로 표준화한 후에 거리를 계산
(x-min(A)) / (max(A) - min(A))
- x는 A의 임의의 관측값
std <- function(X) {
return((X-min(X)) / (max(X)-min(X)))
}
mydata <- apply(iris[,1:4], 2, std)
fit <- kmeans(x=mydata, centers=3)
fit
> mydata <- apply(iris[,1:4], 2, std)
> fit <- kmeans(x=mydata, centers=3)
> fit
K-means clustering with 3 clusters of sizes 61, 39, 50
Cluster means:
Sepal.Length Sepal.Width Petal.Length Petal.Width
1 0.4412568 0.3073770 0.57571548 0.54918033
2 0.7072650 0.4508547 0.79704476 0.82478632
3 0.1961111 0.5950000 0.07830508 0.06083333
Clustering vector:
[1] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2
[52] 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1
[103] 2 2 2 2 1 2 2 2 2 2 2 1 2 2 2 2 2 1 2 1 2 1 2 2 1 1 2 2 2 2 2 1 1 2 2 2 1 2 2 2 1 2 2 2 1 2 2 1
Within cluster sum of squares by cluster:
[1] 3.079830 2.073324 1.829062
(between_SS / total_SS = 83.0 %)
Available components:
[1] "cluster" "centers" "totss" "withinss" "tot.withinss" "betweenss" "size"
[8] "iter" "ifault"
단계
- 그룹을 모르는 데이터 P에 대해 이미 그룹이 알려진 데이터 중 P와 가장 가까이에 있는 k개의 데이터를 수집
- k개의 데이터가 가장 많이 속해 있는 군집을 P의 군집으로 결정
library(class)
# 훈련용 데이터와 테스트용 데이터 준비
tr.idx <- c(1:25, 51:75, 101:125) # 훈련용 데이터의 인덱스
ds.tr <- iris[tr.idx, 1:4] # 훈련용 데이터셋
ds.ts <- iris[-tr.idx, 1:4] # 테스트용 데이터셋
cl.tr <- factor(iris[tr.idx, 5]) # 훈련용 데이터셋의 그룹 정보
cl.ts <- factor(iris[-tr.idx, 5]) # 테스트용 데이터셋의 그룹 정보
pred <- knn(ds.tr, ds.ts, cl.tr, k=3, prob=T)
pred
acc <- mean(pred==cl.ts) # 예측 정확도
acc
table(pred, cl.ts) # 예측값과 실제값 비교 통계
> pred
[1] setosa setosa setosa setosa setosa setosa setosa setosa setosa
[10] setosa setosa setosa setosa setosa setosa setosa setosa setosa
[19] setosa setosa setosa setosa setosa setosa setosa versicolor versicolor
[28] virginica versicolor versicolor versicolor versicolor versicolor virginica versicolor versicolor
[37] versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor
[46] versicolor versicolor versicolor versicolor versicolor virginica versicolor versicolor virginica
[55] virginica virginica virginica virginica versicolor virginica virginica virginica virginica
[64] versicolor virginica virginica virginica virginica virginica virginica virginica virginica
[73] virginica virginica virginica
attr(,"prob")
[1] 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000
[11] 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000
[21] 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 0.6666667 1.0000000 1.0000000
[31] 1.0000000 1.0000000 1.0000000 0.6666667 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000
[41] 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000
[51] 1.0000000 0.6666667 0.7500000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 0.5000000 1.0000000
[61] 1.0000000 1.0000000 1.0000000 0.6666667 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000
[71] 1.0000000 0.6666667 1.0000000 1.0000000 0.6666667
Levels: setosa versicolor virginica
> acc <- mean(pred==cl.ts) # 예측 정확도
> acc
[1] 0.92
> table(pred, cl.ts) # 예측값과 실제값 비교 통계
cl.ts
pred setosa versicolor virginica
setosa 25 0 0
versicolor 0 23 4
virginica 0 2 21
knn()
ds.tr
은 훈련용 데이터셋ds.ts
는 테스트용 데이터셋cl.tr
은 훈련용 데이터셋의 그룹 정보k=3
은 최근점 이웃의 개수prob=T
는 예측된 그룹에 대한 지지 확률의 표시 여부
k-최근접 이웃 분류의 추가 설명
- k값은 sqrt(관측값의 개수)보다 작은 것이 좋다고 알려짐
- 그룹을 예측할 때 다수결에서 동수가 나오면 knn()은 임의로 선택함
- 단점은 계산 시간이 오래걸리고, 메모리 요구량이 큼
- 데이터를 임의로 훈련용과 테스트용으로 나누어 모델을 개발하는 과정을 여러 번 반복하여 그곳에서 도출되는 예측 정확도의 평균을 구하는 것을 체계화한 방법론
library(cvTools)
k <- 10 # 10-fold
folds <- cvFolds(nrow(iris), K=k) # 폴드 생성
acc <- c() # 폴드별 예측 정확도 저장용 벡터
for (i in 1:k) {
ts.idx <- folds$which==i # 테스트용 데이터의 인덱스
ds.tr <- iris[-ts.idx, 1:4] # 훈련용 데이터셋
ds.ts <- iris[ts.idx, 1:4] # 테스트용 데이터셋
cl.tr <- factor(iris[-ts.idx, 5]) # 훈련용 데이터셋의 그룹 정보
cl.ts <- factor(iris[ts.idx, 5]) # 테스트용 데이터셋의 그룹 정보
pred <- knn(ds.tr, ds.ts, cl.tr, k=5)
acc[i] <- mean(pred==cl.ts) # 예측 정확도
}
acc # 폴드별 예측 정확도
mean(acc) # 폴드평균 예측 정확도
> acc # 폴드별 예측 정확도
[1] 0.9333333 1.0000000 0.9333333 0.9333333 1.0000000 1.0000000 0.9333333 1.0000000 1.0000000 0.9333333
> mean(acc) # 폴드평균 예측 정확도
[1] 0.9666667
setwd("c:/Users/32184808/Desktop/R_study/data_file")
library(ggplot2)
library(ggmap)
library(readxl)
files <- c("201512","201606","201612","201706","201712")
columns <- c("상가업소번호","상호명","상권업종대분류명","상권업종중분류명",
"상권업종소분류명","시군구명","행정동명","경도","위도")
ds.total <- NULL
for (i in 1:length(files)) {
filename <- paste("seoul_",files[i],".xlsx",sep="")
cat("read",filename,"...\n") # 읽을 파일 이름 출력
ds <- read_excel(filename) # 엑셀 파일 읽기
ds <- data.frame(ds)
ds <- ds[,columns] # 분석에 필요한 변수만 추출
ds$수집연월 <- rep(i, nrow(ds)) # 데이터 수집 시점
ds.total <- rbind(ds.total,ds) # 데이터 통합
}
head(ds.total)
str(ds.total)
unique(ds.total$수집연월) # 수집연월
unique(ds.total$상권업종대분류명) # 상권업종 대분류
unique(ds.total$상권업종중분류명) # 상권업종 중분류
unique(ds.total$상권업종소분류명) # 상권업종 소분류
# NA 포함여부 확인
sum(is.na(ds.total))
# 201712 수집 데이터만 추출
ds.201712 <- subset(ds.total, ds.total$수집연월==5)
dim(ds.201712)
> str(ds.total)
'data.frame': 1941432 obs. of 10 variables:
$ 상가업소번호 : num 20316431 20252211 20294848 20469870 20468674 ...
$ 상호명 : chr "서민시대참짜장" "별난왕족발보쌈" "상근삼계탕" "다사랑커피숍" ...
$ 상권업종대분류명: chr "음식" "음식" "음식" "음식" ...
$ 상권업종중분류명: chr "중식" "한식" "닭/오리요리" "커피점/카페" ...
$ 상권업종소분류명: chr "중국음식/중국집" "족발/보쌈전문" "삼계탕전문" "커피전문점/카페/다방" ...
$ 시군구명 : chr "관악구" "관악구" "관악구" "관악구" ...
$ 행정동명 : chr "은천동" "은천동" "은천동" "은천동" ...
$ 경도 : num 127 127 127 127 127 ...
$ 위도 : num 37.5 37.5 37.5 37.5 37.5 ...
$ 수집연월 : int 1 1 1 1 1 1 1 1 1 1 ...
> unique(ds.total$수집연월) # 수집연월
[1] 1 2 3 4 5
> unique(ds.total$상권업종대분류명) # 상권업종 대분류
[1] "음식" "소매" "생활서비스" "부동산" "관광/여가/오락" "의료"
[7] "학문/교육" "숙박" "스포츠"
> unique(ds.total$상권업종중분류명) # 상권업종 중분류
[1] "중식" "한식" "닭/오리요리"
[4] "커피점/카페" "건강/미용식품" "유흥주점"
[7] "음/식료품소매" "분식" "양식"
[10] "패스트푸드" "철물/난방/건설자재소매" "별식/퓨전요리"
[13] "이/미용/건강" "종합소매점" "세탁/가사서비스"
[16] "부동산중개" "선물/팬시/기념품" "PC/오락/당구/볼링등"
[19] "부동산임대" "병원" "도서관/독서실"
[22] "개인/가정용품수리" "페인트/유리제품소매" "가전제품소매"
[25] "법무세무회계" "광고/인쇄" "평가/개발/관리"
[28] "인력/고용/용역알선" "개인서비스" "일식/수산물"
...
[760] "스킨스쿠버강습" "쿵후도장" "스키장"
[763] "프로야구" "수영장" "축구장"
[766] "행글라이더" "실내테니스장" "패러글라이딩"
[769] "게이트볼장" "프로스포츠경기운영" "야구장"
[772] "프로골프"
>
> # NA 포함여부 확인
> sum(is.na(ds.total))
[1] 0
>
> # 201712 수집 데이터만 추출
> ds.201712 <- subset(ds.total, ds.total$수집연월==5)
> dim(ds.201712)
[1] 321436 10
설명
- ds.total에는 총 1,941,432건의 상가점포 데이터가 포함되어 있고 변수는 10개
- 수집연월은 1,2,3,4,5 형태로 저장되어 있음
- 상가점포 업종 대분류는 총 9개의 그룹으로 구성
- 상가점포 업종 중분류는 총 102개의 그룹으로 구성
- 상가점포 업종 소분류는 총 772개의 그룹으로 구성
- 결측값은 없음
- 사용할 데이터인 2017년 12월 수집 데이터는 총 321,436건
# 업종별 점포수(대분류)
store.level_1 <- aggregate(ds.201712[,1],
by=list(대분류=ds.201712$상권업종대분류명),
FUN=length)
store.level_1
names(store.level_1)[2] = c("count")
ggplot(store.level_1, aes(x=대분류, y=count)) +
geom_bar(stat="identity", width=0.7, fill="steelblue") +
ggtitle("업종별 점포수") +
theme(plot.title = element_text(color="black", size=14, face="bold"))
> store.level_1
대분류 x
1 관광/여가/오락 8968
2 부동산 12677
3 생활서비스 50550
4 소매 99494
5 숙박 2582
6 스포츠 3112
7 음식 103086
8 의료 15065
9 학문/교육 25902
설명
- 데이터 건수 확인에 list() 사용
- 업종별 점포수를 나타내는 두 번째 열의 이름이 x로 되어 있어 count로 변경
- 음식과 소매가 압도적으로 많음
# 구별 점포수
store.region <- aggregate(ds.201712[,1],
by=list(구이름=ds.201712$시군구명),
FUN=length)
store.region
names(store.region)[2] = c("count")
ggplot(store.region, aes(x=구이름, y=count)) +
geom_bar(stat="identity", width=0.7, fill="steelblue") +
ggtitle("구별 점포수") +
theme(plot.title=element_text(color="black",size=14,face="bold"),
axis.text.x=element_text(angle=45))
> store.region
구이름 x
1 강남구 29394
2 강동구 13658
3 강북구 8223
4 강서구 12354
5 관악구 13616
6 광진구 14147
7 구로구 12140
8 금천구 9467
9 노원구 11271
10 도봉구 8174
11 동대문구 12581
12 동작구 8543
13 마포구 12701
14 서대문구 9449
15 서초구 17038
16 성동구 9138
17 성북구 13447
18 송파구 15456
19 양천구 10231
20 영등포구 16471
21 용산구 10021
22 은평구 10581
23 종로구 14318
24 중구 18358
25 중랑구 10659
설명
- 시군구의 이름 열을 기준으로 점포수 집계
- 마찬가지로 두 번째 열 이름을 count로 변경
- 강남구가 다른 구보다 점포수가 많음
# 지도 위에 구별 점포수 표시
store.region.loc <- aggregate(ds.201712[,c("경도","위도")],
by=list(구이름=ds.201712$시군구명),
FUN=mean)
store.region <- data.frame(store.region, store.region.loc[,2:3])
register_google(key="~~~")
cen <- c(mean(store.region$경도),mean(store.region$위도))
map <- get_googlemap(center=centermaptype="roadmap",
size=c(640, 640),
zoom=11)
gmap <- ggmap(map)
gmap+geom_point(data=store.region,
aes(x=경도, y=위도, size=count),
alpha=0.5, col="red") +
scale_size_continuous(range=c(1,15)) +
geom_text(data=store.region,
aes(x=경도, y=위도),
size=3,
label=store.region$구이름)
설명
- 점포의 위치를 구별로 평균을 계산하여 store.region.loc에 저장
- store.region에 구의 위도와 경도 정보(
store.region.loc[,2:3]
)
# 점포수가 많은 상위 10개 동 확인
store.dong <- aggregate(ds.201712[,1],
by=list(동이름=ds.201712$행정동명),
FUN=length)
store.dong
names(store.dong)[2] = c("count")
store.dong <- store.dong[order(store.dong$count, decreasing=T),]
dong.top10 <- store.dong[1:10,]
dong.top10
ggplot(dong.top10, aes(x=reorder(동이름, -count), y=count)) +
geom_bar(stat="identity",width=0.7, fill="steelblue") +
ggtitle("점포수 많은 상위 10개동") +
theme(plot.title=element_text(color="black",size=14,face="bold"),
axis.text.x=element_text(angle=45))
> store.dong
동이름 x
1 가락1동 131
2 가락2동 633
3 가락본동 956
4 가리봉동 643
5 가산동 2874
6 가양1동 942
7 가양2동 210
8 가양3동 189
9 가회동 505
10 갈현1동 922
11 갈현2동 975
12 강일동 279
13 개봉1동 856
14 개봉2동 515
15 개봉3동 342
...
420 후암동 318
421 휘경1동 363
422 휘경2동 400
423 흑석동 627
> dong.top10
동이름 count
278 역삼1동 5120
353 종로1.2.3.4가동 4601
285 영등포동 3750
418 회현동 3579
188 서교동 3488
238 신당동 3205
74 대치4동 3171
5 가산동 2874
245 신사동 2696
261 신촌동 2632
설명
- 역삼1동에 가장 많은 점포수가 존재
x=reorder(동이름, -count)
는 x축에 표시되는 동 이름을 가나다순으로 하지 말고 count의 내림차순으로 표시하라는 의미
# 업종별 점포수의 변화
store.change <- aggregate(ds.total[,1],
by=list(연월=ds.total$수집연월,
업종대분류=ds.total$상권업종대분류명),
FUN=length)
head(store.change)
names(store.change)[3] <- c("count")
ggplot(store.change, aes(x=연월, y=count, colour=업종대분류, group=업종대분류)) +
geom_line() +
geom_point(size=6, shape=19, alpha=0.5) +
ggtitle("업종별 점포수 변화 (대분류)") +
ylab("점포수") +
scale_x_continuous(breaks=1:5,
labels=files) +
theme(plot.title=element_text(color="black",size=14,face="bold"))
> head(store.change)
연월 업종대분류 x
1 1 관광/여가/오락 11846
2 2 관광/여가/오락 14235
3 3 관광/여가/오락 9870
4 4 관광/여가/오락 9804
5 5 관광/여가/오락 8968
6 1 부동산 16843
설명
- 전반적으로 2016년 6월을 기점으로 점포수가 감소하는 추세 확인
- 점포수가 많은 소매점과 음식점의 변화가 큼
# 점포수 변화가 큰 상위 10개 업종
store.tmp <- aggregate(ds.total[,1],
by=list(연월=ds.total$수집연월,
업종소분류=ds.total$상권업종소분류명),
FUN=length)
names(store.tmp)[3] <- c("count")
store.201512 <- store.tmp[store.tmp$연월==1,]
names(store.201512)[3] <- c("cnt_2015")
store.201712 <- store.tmp[store.tmp$연월==5,]
names(store.201712)[3] <- c("cnt_2017")
store.diff <- merge(store.201512[,2:3], store.201712[,2:3])
store.diff$diff <- abs(store.diff$cnt_2015-store.diff$cnt_2017)
store.diff <- store.diff[order(by=store.diff$diff, decreasing=T),]
top10 <- store.diff[1:10,1]
top10
store.change <- subset(store.tmp, store.tmp$업종소분류 %in% top10)
ggplot(store.change, aes(x=연월, y=count, colour=업종소분류, group=업종소분류)) +
geom_line() +
geom_point(size=6, shape=19, alpha=0.5) +
ggtitle("점포수 변화 Top 10 업종(소분류)") +
ylab("점포수") +
scale_x_continuous(breaks=1:5,
labels=files) +
theme(plot.title=element_text(color="black",size=14,face="bold"))
> top10
[1] "일반의류" "종합소매" "사업경영상담" "통신판매" "화장품판매점"
[6] "자동판매기운영" "학원-입시" "학원(종합)" "건물분양-종합" "한식/백반/한정식"
설명
- merge()를 이용하여 store.201512와 store.201712의 자료를 하나로 통합하여 store.diff에 저장한 후 점포수의 차이를 diff열에 저장
- 전반적으로 점포수가 감소하는 추세에 있는데 '종합소매' 업종만 점포수가 비약적으로 증가했음
# 구별 점포수의 변화
store.gu <- aggregate(ds.total[,1],
by=list(연월=ds.total$수집연월,
구이름=ds.total$시군구명),
FUN=length)
names(store.gu)[3] <- c("count")
ggplot(store.gu, aes(x=연월, y=count, colour=구이름, group=구이름)) +
geom_line() +
geom_point(size=6, shape=19, alpha=0.5) +
ggtitle("구별 점포수 변화 (대분류)") +
ylab("점포수") +
scale_x_continuous(breaks=1:5,
labels=files) +
theme(plot.title=element_text(color="black",size=14,face="bold"))
설명
- 점포수가 많은 강남구의 변화가 크게 나타남
# 점포수 변화가 큰 상위 10개 동
store.tmp <- aggregate(ds.total[,1],
by=list(연월=ds.total$수집연월,
동이름=ds.total$행정동명),
FUN=length)
names(store.tmp)[3] <- c("count")
store.dong.201512 <- store.tmp[store.tmp$연월==1,]
names(store.dong.201512)[3] <- c("cnt_2015")
store.dong.201712 <- store.tmp[store.tmp$연월==5,]
names(store.dong.201712)[3] <- c("cnt_2017")
store.diff <- merge(store.dong.201512[,2:3], store.dong.201712[,2:3])
store.diff$diff <- abs(store.diff$cnt_2015-store.diff$cnt_2017)
store.diff <- store.diff[order(by=store.diff$diff, decreasing=T),]
top10 <- store.diff[1:10,1] # 동명
top10
store.change <- subset(store.tmp, store.tmp$동이름 %in% top10)
ggplot(store.change, aes(x=연월, y=count, colour=동이름, group=동이름)) +
geom_line() +
geom_point(size=6, shape=19, alpha=0.5) +
ggtitle("점포수 변화 Top 10 동") +
ylab("점포수") +
scale_x_continuous(breaks=1:5,
labels=files) +
theme(plot.title=element_text(color="black",size=14,face="bold"))
> top10
[1] "역삼1동" "서교동" "논현1동" "서초3동" "명동"
[6] "신사동" "종로1.2.3.4가동" "삼성2동" "삼성1동" "압구정동"
ds.yeoksam <- subset(ds.total, ds.total$수집연월==5 &
ds.total$행정동명=="역삼1동")
# 점포를 업종별로 구분하여 지도에 표시
cen <- c(mean(ds.yeoksam$경도), mean(ds.yeoksam$위도))
map <- get_googlemap(center=cen,
maptype="roadmap",
size=c(640,640),
zoom=15)
gmap <- ggmap(map)
gmap+geom_point(data=ds.yeoksam,
aes(x=경도, y=위도, color=상권업종대분류명), size=2, alpha=0.7) +
labs(x="Longitude", y="Latitude",
title="역삼1동 업종별 점포", color="업종")
# 커피 점포만 지도에 표시
ds.yeoksam2 <- subset(ds.yeoksam, ds.yeoksam$상권업종소분류명=="커피전문점/카페/다방")
gmap+geom_point(data=ds.yeoksam2,
aes(x=경도, y=위도), size=2, alpha=0.5, col="red") +
labs(x="Longitude", y="Latitude",
title="역삼1동 커피점")