Skip to content

Latest commit

 

History

History
721 lines (646 loc) · 29.6 KB

220517.md

File metadata and controls

721 lines (646 loc) · 29.6 KB

군집화와 분류의 개념

군집화

  • 주어진 대상 데이터들을 유사성이 높은 것끼리 묶어주는 기술
  • 이 묶음을 군집, 범주, 그룹 등의 용어로 부름
  • 비지도학습

분류

  • 그룹의 형태로 알려진 데이터들이 있을 때 그룹을 모르는 어떤 데이터에 대해 어느 그룹에 속하는지를 예측하는 기술
  • 지도학습

k-평균 군집화의 과정

k-평균 군집화 알고리즘

  • 사용하기 위해서는 군집의 개수(k)를 정해야 함
  • 데이터의 군집이 몇 개 존재할지 사전에 정할 수 있는 경우가 있고 어려운 경우가 있음

단계 (k=2)

  1. 대상 데이터셋 준비
  2. 산점도 상에 임의의 점 2개를 만듦 (이 점은 각 군집의 중심점이 됨)
  3. 산점도 상의 점들 하나하나와 임의의 점 2개와의 거리를 계산하여 두 점 중 가까운 쪽으로 군집을 형성
  4. 두 개의 군집에서 중심점을 다시 계산하고 기존의 두 점의 위치를 새로 계산한 중심점 위치로 이동
  5. 4단계의 과정 반복
  6. 두 점의 위치가 더 이상 변동되지 않으면 군집의 중심점에 도달한 것으로 반복을 중단
  7. 마지막으로 각 점들은 두 점 중 가까운 군집으로 표시하고 군집화 종료

R에서의 k-평균 군집화

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

Rplot26

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"    

k-최근접 이웃 분류의 방법

단계

  1. 그룹을 모르는 데이터 P에 대해 이미 그룹이 알려진 데이터 중 P와 가장 가까이에 있는 k개의 데이터를 수집
  2. k개의 데이터가 가장 많이 속해 있는 군집을 P의 군집으로 결정

R에서의 k-최근접 이웃 분류

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()은 임의로 선택함
  • 단점은 계산 시간이 오래걸리고, 메모리 요구량이 큼

k-fold 교차 검증의 방법

  • 데이터를 임의로 훈련용과 테스트용으로 나누어 모델을 개발하는 과정을 여러 번 반복하여 그곳에서 도출되는 예측 정확도의 평균을 구하는 것을 체계화한 방법론

R에서의 k-fold 교차 검증

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

Rplot27

설명

  • 데이터 건수 확인에 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

Rplot28

설명

  • 시군구의 이름 열을 기준으로 점포수 집계
  • 마찬가지로 두 번째 열 이름을 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개 동 확인

# 점포수가 많은 상위 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

Rplot29

설명

  • 역삼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

Rplot30

설명

  • 전반적으로 2016년 6월을 기점으로 점포수가 감소하는 추세 확인
  • 점포수가 많은 소매점과 음식점의 변화가 큼

점포수 변화가 큰 상위 10개 업종

# 점포수 변화가 큰 상위 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] "자동판매기운영"   "학원-입시"        "학원(종합)"       "건물분양-종합"    "한식/백반/한정식"

Rplot31

설명

  • 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"))

Rplot32

설명

  • 점포수가 많은 강남구의 변화가 크게 나타남

점포수 변화가 큰 상위 10개 동 확인

# 점포수 변화가 큰 상위 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동"         "압구정동"   

Rplot33

점포를 업종별로 구분하여 지도에 표시

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동 커피점")