서울시 범죄 현황

서울시는 25개의 자치구로 구성되어 있다. 서울시 5대 주요 범죄 발생 및 검거 데이터를 이용하여 각 자치구의 범죄현황에 대해 탐색하고자 한다.

분석에 사용한 데이터는 다음과 같다.

패키지 준비

library(tidyverse)
## Warning: 패키지 'readr'는 R 버전 4.1.1에서 작성되었습니다
library(stringr)
library(gridExtra)
library(RColorBrewer)
library(GGally)

데이터 불러오기 및 정리 (Import & Tidy)

서울시 관서별 5대 주요 범죄 데이터(2000년 ~ 2017년) 불러오기

scrime <- read.csv("data/seoul_crime_2000_2017.csv", 
                   stringsAsFactors = FALSE, encoding = "euc-kr")
str(scrime)
## 'data.frame':    5580 obs. of  5 variables:
##  $ 구분    : chr  "중부" "중부" "중부" "중부" ...
##  $ 죄종    : chr  "살인" "살인" "강도" "강도" ...
##  $ 발생검거: chr  "발생" "검거" "발생" "검거" ...
##  $ 건수    : int  1 1 17 15 14 14 601 569 1783 1762 ...
##  $ year    : int  2000 2000 2000 2000 2000 2000 2000 2000 2000 2000 ...

서울시 범죄 데이터 정리하기

# 2017년 기준으로 분석할 것이기 때문에 2017년 데이터만 추출
scrime <- scrime %>% 
  filter(year == 2017)
# 분석의 편의를 위해 '발생검거'열을 2개의 열(발생, 검거) 로 나누고자 함
scrime <- scrime %>% 
  spread(key = "발생검거", value = "건수")
str(scrime)
## 'data.frame':    155 obs. of  5 variables:
##  $ 구분: chr  "강남" "강남" "강남" "강남" ...
##  $ 죄종: chr  "강간" "강도" "살인" "절도" ...
##  $ year: int  2017 2017 2017 2017 2017 2017 2017 2017 2017 2017 ...
##  $ 검거: int  366 16 6 787 1942 169 12 6 949 2109 ...
##  $ 발생: int  456 13 6 2069 2229 172 10 5 1645 2429 ...
# 죄종을 5개의 열로 나누고 각 열별로 검거와 발생을 연결하여 정리하기
scrime <- scrime %>% 
  nest(검거, 발생, .key = "value_col") %>% 
  spread(key = "죄종", value = value_col) %>% 
  unnest(강간, 강도, 살인, 절도, 폭력, .sep = '')
## Warning: All elements of `...` must be named.
## Did you want `value_col = c(검거, 발생)`?
## Warning: unnest() has a new interface. See ?unnest for details.
## Try `df %>% unnest(c(강간, 강도, 살인, 절도, 폭력))`, with `mutate()` if needed
## Warning: The `.sep` argument of `unnest()` is deprecated as of tidyr 1.0.0.
## Use `names_sep = ''` instead.
str(scrime)
## tibble [31 x 12] (S3: tbl_df/tbl/data.frame)
##  $ 구분    : chr [1:31] "강남" "강동" "강북" "강서" ...
##  $ year    : int [1:31] 2017 2017 2017 2017 2017 2017 2017 2017 2017 2017 ...
##  $ 강간검거: int [1:31] 366 169 153 253 323 208 181 212 62 155 ...
##  $ 강간발생: int [1:31] 456 172 208 316 379 261 328 240 94 180 ...
##  $ 강도검거: int [1:31] 16 12 5 6 6 8 6 5 3 7 ...
##  $ 강도발생: int [1:31] 13 10 7 4 7 13 8 5 3 9 ...
##  $ 살인검거: int [1:31] 6 6 8 11 7 5 8 5 0 4 ...
##  $ 살인발생: int [1:31] 6 5 8 11 8 6 7 5 1 4 ...
##  $ 절도검거: int [1:31] 787 949 635 1113 1152 1168 869 674 400 757 ...
##  $ 절도발생: int [1:31] 2069 1645 1014 1888 1979 2220 1725 1141 785 1538 ...
##  $ 폭력검거: int [1:31] 1942 2109 2023 2544 2666 1900 2344 1676 780 2124 ...
##  $ 폭력발생: int [1:31] 2229 2429 2156 2916 3152 2146 2827 1874 863 2478 ...
# 구분(경찰서명)의 앞과 뒤에 "서울"과 "경찰서" 붙이기(예, 중부 -> 서울중부경찰서)
scrime <- scrime %>% 
  mutate(구분 = paste0("서울", 구분, "경찰서"))
scrime %>% print(n = Inf)
## # A tibble: 31 x 12
##    구분       year 강간검거 강간발생 강도검거 강도발생 살인검거 살인발생 절도검거
##    <chr>     <int>    <int>    <int>    <int>    <int>    <int>    <int>    <int>
##  1 서울강남~  2017      366      456       16       13        6        6      787
##  2 서울강동~  2017      169      172       12       10        6        5      949
##  3 서울강북~  2017      153      208        5        7        8        8      635
##  4 서울강서~  2017      253      316        6        4       11       11     1113
##  5 서울관악~  2017      323      379        6        7        7        8     1152
##  6 서울광진~  2017      208      261        8       13        5        6     1168
##  7 서울구로~  2017      181      328        6        8        8        7      869
##  8 서울금천~  2017      212      240        5        5        5        5      674
##  9 서울남대~  2017       62       94        3        3        0        1      400
## 10 서울노원~  2017      155      180        7        9        4        4      757
## 11 서울도봉~  2017      115      104        3        3        1        1      417
## 12 서울동대~  2017      149      165        5        3       10       11     1017
## 13 서울동작~  2017      173      396        9        7        1        1      593
## 14 서울마포~  2017      429      500        8        8        3        3      837
## 15 서울방배~  2017       60       65        5        4        2        1      176
## 16 서울서대~  2017      181      202        2        1        4        4      719
## 17 서울서부~  2017       79       93        2        2        3        3      375
## 18 서울서초~  2017      223      405        2        9        8        8      659
## 19 서울성동~  2017      106      132        3        3        1        1      543
## 20 서울성북~  2017       72      107        5        5        5        5      332
## 21 서울송파~  2017      242      288        3        1        6        6     1026
## 22 서울수서~  2017      130      151        8        7        1        1      596
## 23 서울양천~  2017      122      138        2        3        2        3      756
## 24 서울영등~  2017      267      455        5        5       13       15     1108
## 25 서울용산~  2017      289      327        4        5        1        1      626
## 26 서울은평~  2017      134      137        2        2        3        3      559
## 27 서울종로~  2017      103      131        4        5        3        5      360
## 28 서울종암~  2017       62       66        3        3        2        2      371
## 29 서울중랑~  2017      144      172        4        3        5        5      813
## 30 서울중부~  2017       87      173        6        6        0        0      489
## 31 서울혜화~  2017       70      122        4        5        2        2      298
## # ... with 3 more variables: 절도발생 <int>, 폭력검거 <int>, 폭력발생 <int>

경찰서의 주소를 찾아 경찰서가 위치한 자치구 변수 추가

# 경찰서 주소가 들어있는 데이터 불러오기
police_addr <- read.csv("data/police_address.csv", stringsAsFactors = FALSE)
str(police_addr)
## 'data.frame':    273 obs. of  4 variables:
##  $ province: chr  "서울" "서울" "서울" "서울" ...
##  $ office  : chr  "서울지방경찰청" "서울강남경찰서" "서울강동경찰서" "서울강북경찰서" ...
##  $ address : chr  "서울시 종로구 사직로8길 31" "서울시 강남구 테헤란로 114길 11" "서울시 강동구 성내로 57" "서울시 강북구 오패산로 406" ...
##  $ website : chr  "http://www.smpa.go.kr/" "http://www.smpa.go.kr/gn/" "http://www.smpa.go.kr/gd/" "http://www.smpa.go.kr/gb/" ...
# 엑셀 vlookup과 유사한 함수 (this=찾는값, df=데이터, key=찾는변수, value=얻는값 )
vlookup <- function(this, df, key, value) {
  m <- match(this, df[[key]])
  df[[value]][m]
}
# 경찰서명에 맞는 주소를 찾아 새로운 변수에 입력하기
scrime <- scrime %>% 
  mutate(주소 = vlookup(구분, police_addr, "office", "address"))
scrime %>% select(구분, 주소) %>% print(n = Inf)
## # A tibble: 31 x 2
##    구분             주소                           
##    <chr>            <chr>                          
##  1 서울강남경찰서   서울시 강남구 테헤란로 114길 11
##  2 서울강동경찰서   서울시 강동구 성내로 57        
##  3 서울강북경찰서   서울시 강북구 오패산로 406     
##  4 서울강서경찰서   서울시 양천구 화곡로 73        
##  5 서울관악경찰서   서울시 관악구 관악로5길 33     
##  6 서울광진경찰서   서울시 광진구 자양로 167       
##  7 서울구로경찰서   서울시 구로구 가마산로 235     
##  8 서울금천경찰서   서울시 금천구 시흥대로73길 50  
##  9 서울남대문경찰서 서울시 중구 한강대로 410       
## 10 서울노원경찰서   서울시 노원구 노원로 283       
## 11 서울도봉경찰서   서울시 도봉구 노해로 403       
## 12 서울동대문경찰서 서울시 동대문구 약령시로21길 29
## 13 서울동작경찰서   서울시 동작구 노량진로 148     
## 14 서울마포경찰서   서울시 마포구 마포대로 183     
## 15 서울방배경찰서   서울시 서초구 동작대로 204     
## 16 서울서대문경찰서 서울 서대문구 통일로 113       
## 17 서울서부경찰서   서울시 은평구 통일로 757       
## 18 서울서초경찰서   서울시 서초구 반포대로 179     
## 19 서울성동경찰서   서울시 성동구 왕십리광장로 9   
## 20 서울성북경찰서   서울 성북구 보문로 170         
## 21 서울송파경찰서   서울시 송파구 중대로 221       
## 22 서울수서경찰서   서울시 강남구 개포로 617       
## 23 서울양천경찰서   서울시 양천구 목동동로 99      
## 24 서울영등포경찰서 서울시 영등포구 국회대로 608   
## 25 서울용산경찰서   서울시 용산구 원효로89길 24    
## 26 서울은평경찰서   서울시 은평구 연서로 365       
## 27 서울종로경찰서   서울시 종로구 율곡로 46        
## 28 서울종암경찰서   서울시 성북구 종암로 135       
## 29 서울중랑경찰서   서울시 중랑구 신내역로3길 40-10
## 30 서울중부경찰서   서울시 중구 수표로 27          
## 31 서울혜화경찰서   서울시 종로구 창경궁로 112-16
# 주소에서 두번째에 있는 자치구 이름만 추출하여 새로운 변수(자치구)에 입력하기
scrime <- scrime %>% 
  separate(주소, c(NA, "자치구"), sep = " ", extra = "drop")
# 자치구를 기준으로 정렬하여 경찰서와 자치구 출력
scrime %>% select(구분, 자치구) %>% arrange(자치구) %>%  print(n = Inf)
## # A tibble: 31 x 2
##    구분             자치구  
##    <chr>            <chr>   
##  1 서울강남경찰서   강남구  
##  2 서울수서경찰서   강남구  
##  3 서울강동경찰서   강동구  
##  4 서울강북경찰서   강북구  
##  5 서울관악경찰서   관악구  
##  6 서울광진경찰서   광진구  
##  7 서울구로경찰서   구로구  
##  8 서울금천경찰서   금천구  
##  9 서울노원경찰서   노원구  
## 10 서울도봉경찰서   도봉구  
## 11 서울동대문경찰서 동대문구
## 12 서울동작경찰서   동작구  
## 13 서울마포경찰서   마포구  
## 14 서울서대문경찰서 서대문구
## 15 서울방배경찰서   서초구  
## 16 서울서초경찰서   서초구  
## 17 서울성동경찰서   성동구  
## 18 서울성북경찰서   성북구  
## 19 서울종암경찰서   성북구  
## 20 서울송파경찰서   송파구  
## 21 서울강서경찰서   양천구  
## 22 서울양천경찰서   양천구  
## 23 서울영등포경찰서 영등포구
## 24 서울용산경찰서   용산구  
## 25 서울서부경찰서   은평구  
## 26 서울은평경찰서   은평구  
## 27 서울종로경찰서   종로구  
## 28 서울혜화경찰서   종로구  
## 29 서울남대문경찰서 중구    
## 30 서울중부경찰서   중구    
## 31 서울중랑경찰서   중랑구

구를 기준으로 정렬한 결과, 7개 구에 2개의 경찰서가 있는 것으로 나타남. 서울강서경찰서는 현재 양천구 임시청사에 있으나 관할구역은 강서구임.

# 서울강서경찰서의 자치구를 강서구로 수정함
scrime <- scrime %>% 
  mutate(자치구 = replace(자치구, which(구분 == "서울강서경찰서"), "강서구"))

서울시 자치구의 수는 25개임. 강남과 수서는 강남구, 서초와 방배는 서초구, 성북과 종암은 성북구, 서부와 은평은 은평구, 종로와 혜화는 종로구, 중부와 남대문은 중구를 관할함.

# 자치구를 기준으로 변수들을 통합함(구분, year 변수는 삭제)
scrime <- scrime %>% 
  group_by(자치구) %>% 
  summarise(강간검거 = sum(강간검거), 
            강간발생 = sum(강간발생),
            강도검거 = sum(강도검거),
            강도발생 = sum(강도발생),
            살인검거 = sum(살인검거),
            살인발생 = sum(살인발생),
            절도검거 = sum(절도검거),
            절도발생 = sum(절도발생),
            폭력검거 = sum(폭력검거),
            폭력발생 = sum(폭력발생))

이상으로 2017년 기준 서울시 자치구별 5대 범죄의 발생과 검거 건수를 정리함

# 서울시 범죄 데이터 정리 결과 보기
scrime %>% print(n = Inf, width = Inf)
## # A tibble: 25 x 11
##    자치구   강간검거 강간발생 강도검거 강도발생 살인검거 살인발생 절도검거
##    <chr>       <int>    <int>    <int>    <int>    <int>    <int>    <int>
##  1 강남구        496      607       24       20        7        7     1383
##  2 강동구        169      172       12       10        6        5      949
##  3 강북구        153      208        5        7        8        8      635
##  4 강서구        253      316        6        4       11       11     1113
##  5 관악구        323      379        6        7        7        8     1152
##  6 광진구        208      261        8       13        5        6     1168
##  7 구로구        181      328        6        8        8        7      869
##  8 금천구        212      240        5        5        5        5      674
##  9 노원구        155      180        7        9        4        4      757
## 10 도봉구        115      104        3        3        1        1      417
## 11 동대문구      149      165        5        3       10       11     1017
## 12 동작구        173      396        9        7        1        1      593
## 13 마포구        429      500        8        8        3        3      837
## 14 서대문구      181      202        2        1        4        4      719
## 15 서초구        283      470        7       13       10        9      835
## 16 성동구        106      132        3        3        1        1      543
## 17 성북구        134      173        8        8        7        7      703
## 18 송파구        242      288        3        1        6        6     1026
## 19 양천구        122      138        2        3        2        3      756
## 20 영등포구      267      455        5        5       13       15     1108
## 21 용산구        289      327        4        5        1        1      626
## 22 은평구        213      230        4        4        6        6      934
## 23 종로구        173      253        8       10        5        7      658
## 24 중구          149      267        9        9        0        1      889
## 25 중랑구        144      172        4        3        5        5      813
##    절도발생 폭력검거 폭력발생
##       <int>    <int>    <int>
##  1     3130     3411     3956
##  2     1645     2109     2429
##  3     1014     2023     2156
##  4     1888     2544     2916
##  5     1979     2666     3152
##  6     2220     1900     2146
##  7     1725     2344     2827
##  8     1141     1676     1874
##  9     1538     2124     2478
## 10      633     1116     1258
## 11     1547     2093     2249
## 12     1226     1466     1700
## 13     2094     2222     2673
## 14     1230     1393     1676
## 15     1812     2102     2404
## 16     1072     1378     1559
## 17     1344     1627     1902
## 18     2274     2593     3007
## 19     1590     1778     2148
## 20     2304     2619     3190
## 21     1346     2016     2381
## 22     1387     2050     2256
## 23     1644     1837     2143
## 24     1846     1804     2061
## 25     1533     2426     2858

서울시 인구 데이터 불러오기

# 서울시 인구 데이터 불러오기
spop <- read.csv("data/seoul_pop_1992_2018.csv", stringsAsFactors = FALSE)
str(spop)
## 'data.frame':    693 obs. of  16 variables:
##  $ 연도      : int  1992 1992 1992 1992 1992 1992 1992 1992 1992 1992 ...
##  $ 자치구    : chr  "합계" "종로구" "중구" "용산구" ...
##  $ 세대      : int  3383169 75752 59667 96832 244888 149094 136876 163995 229923 174005 ...
##  $ 인구      : int  10969862 227988 176836 287124 780526 470594 458391 527296 766799 571833 ...
##  $ 남자      : int  5519096 114648 89537 144600 397121 238385 230937 266530 385385 284049 ...
##  $ 여자      : int  5450766 113340 87299 142524 383405 232209 227454 260766 381414 287784 ...
##  $ 한국인    : int  10935230 226240 174605 280671 778385 469843 458109 525943 765975 571171 ...
##  $ 한국인남자: int  5500001 113677 88268 140424 395977 237979 230799 265830 385011 283705 ...
##  $ 한국인여자: int  5435229 112563 86337 140247 382408 231864 227310 260113 380964 287466 ...
##  $ 외국인    : int  34632 1748 2231 6453 2141 751 282 1353 824 662 ...
##  $ 외국인남자: int  19095 971 1269 4176 1144 406 138 700 374 344 ...
##  $ 외국인여자: int  15537 777 962 2277 997 345 144 653 450 318 ...
##  $ 인구밀도  : chr  "18121" "9496" "17701" "13135" ...
##  $ 면적      : chr  "605.36" "24.01" "9.99" "21.86" ...
##  $ 세대당인구: num  3.24 3.01 2.96 2.97 3.19 3.16 3.35 3.22 3.34 3.29 ...
##  $ 고령자    : int  434348 12096 8857 13957 28493 19142 15849 23020 29689 24345 ...

서울시 인구 데이터 정리하기

# 2017년도 자치구, 인구, 한국인, 외국인, 고령자, 인구밀도, 면적 데이터 추출
spop2017 <- spop %>% 
  filter(연도 == 2017) %>% 
  select(자치구, 인구, 한국인, 외국인, 고령자, 세대) 

데이터의 첫번째 행에 있는 합계는 필요 없으로 삭제함

# 첫번째 행(합계) 삭제
spop2017 <- spop2017[-1,]
str(spop2017)  
## 'data.frame':    25 obs. of  6 variables:
##  $ 자치구: chr  "종로구" "중구" "용산구" "성동구" ...
##  $ 인구  : int  164257 134593 244444 312711 372298 366011 412780 455407 328002 346234 ...
##  $ 한국인: int  154770 125709 229161 304808 357703 350647 408226 444055 324479 344166 ...
##  $ 외국인: int  9487 8884 15283 7903 14595 15364 4554 11352 3523 2068 ...
##  $ 고령자: int  26182 21384 36882 41273 43953 55718 59262 66251 56530 53488 ...
##  $ 세대  : int  73594 60412 107666 132902 160798 159938 179132 187112 142533 137378 ...
# 외국인비율과 고령자비율 변수 추가
spop2017 <- spop2017 %>% 
  mutate(외국인비율 = 외국인 / 인구 * 100,
         고령자비율 = 고령자 / 인구 * 100)
head(spop2017)
##     자치구   인구 한국인 외국인 고령자   세대 외국인비율 고령자비율
## 2   종로구 164257 154770   9487  26182  73594   5.775705   15.93966
## 3     중구 134593 125709   8884  21384  60412   6.600640   15.88790
## 4   용산구 244444 229161  15283  36882 107666   6.252148   15.08812
## 5   성동구 312711 304808   7903  41273 132902   2.527254   13.19845
## 6   광진구 372298 357703  14595  43953 160798   3.920247   11.80587
## 7 동대문구 366011 350647  15364  55718 159938   4.197688   15.22304

서울시 CCTV 데이터 불러오기

# 서울시 CCTV 설치 현황(2011년이전 ~ 2018년) 데이터 불러오기
scctv <- read.csv("data/seoul_cctv_b2011_2018.csv", stringsAsFactors = FALSE)
str(scctv)
## 'data.frame':    25 obs. of  10 variables:
##  $ 기관명     : chr  "강 남 구" "강 동 구" "강 북 구" "강 서 구" ...
##  $ 소계       : int  5221 1879 1265 1617 3985 1581 3227 1634 1906 858 ...
##  $ X2011년이전: int  1944 303 243 219 430 470 852 27 481 197 ...
##  $ X2012년    : int  195 387 88 155 56 42 219 17 117 66 ...
##  $ X2013년    : int  316 134 141 118 419 83 349 242 203 8 ...
##  $ X2014년    : int  430 59 74 230 487 87 187 101 80 185 ...
##  $ X2015년    : int  546 144 145 187 609 64 268 382 461 59 ...
##  $ X2016년    : int  765 194 254 190 619 21 326 136 298 155 ...
##  $ X2017년    : int  577 273 1 264 694 468 540 199 110 117 ...
##  $ X2018년    : int  448 385 319 254 671 346 486 530 156 71 ...

서울시 CCTV 데이터 정리하기

데이터는 각 년도별로 설치된 대수와 2018년까지의 소계를 보여주고 있다. 2017년까지 설치된 CCTV 누적대수는 소계에서 2018년 설치대수를 빼는 방식으로 계산하고자 한다.

# 2017년 기준 CCTV 설치누적대수 산출하기
scctv2017 <- scctv %>% 
  mutate(cctv2017 = 소계 - X2018년) %>% 
  select(기관명, cctv2017)
str(scctv2017)
## 'data.frame':    25 obs. of  2 variables:
##  $ 기관명  : chr  "강 남 구" "강 동 구" "강 북 구" "강 서 구" ...
##  $ cctv2017: int  4773 1494 946 1363 3314 1235 2741 1104 1750 787 ...
# 기관명을 자치구로 변수명 변경
scctv2017 <- scctv2017 %>% rename(자치구 = 기관명)
# 자치구 글자 사이에 공백이 있으므로 이를 제거
scctv2017$자치구 <- str_replace_all(scctv2017$자치구, " ", "")
head(scctv2017)
##   자치구 cctv2017
## 1 강남구     4773
## 2 강동구     1494
## 3 강북구      946
## 4 강서구     1363
## 5 관악구     3314
## 6 광진구     1235

자치구를 기준으로 범죄, 인구, CCTV 데이터 병합하기

# scrime, spop2017, scctv2017 병합
seoul_crime_pop_cctv <- list(scrime, spop2017, scctv2017) %>% 
  reduce(left_join, by = "자치구") 
str(seoul_crime_pop_cctv)
## tibble [25 x 19] (S3: tbl_df/tbl/data.frame)
##  $ 자치구    : chr [1:25] "강남구" "강동구" "강북구" "강서구" ...
##  $ 강간검거  : int [1:25] 496 169 153 253 323 208 181 212 155 115 ...
##  $ 강간발생  : int [1:25] 607 172 208 316 379 261 328 240 180 104 ...
##  $ 강도검거  : int [1:25] 24 12 5 6 6 8 6 5 7 3 ...
##  $ 강도발생  : int [1:25] 20 10 7 4 7 13 8 5 9 3 ...
##  $ 살인검거  : int [1:25] 7 6 8 11 7 5 8 5 4 1 ...
##  $ 살인발생  : int [1:25] 7 5 8 11 8 6 7 5 4 1 ...
##  $ 절도검거  : int [1:25] 1383 949 635 1113 1152 1168 869 674 757 417 ...
##  $ 절도발생  : int [1:25] 3130 1645 1014 1888 1979 2220 1725 1141 1538 633 ...
##  $ 폭력검거  : int [1:25] 3411 2109 2023 2544 2666 1900 2344 1676 2124 1116 ...
##  $ 폭력발생  : int [1:25] 3956 2429 2156 2916 3152 2146 2827 1874 2478 1258 ...
##  $ 인구      : int [1:25] 561052 440359 328002 608255 520929 372298 441559 253491 558075 346234 ...
##  $ 한국인    : int [1:25] 556164 436223 324479 601691 503297 357703 410742 235154 554403 344166 ...
##  $ 외국인    : int [1:25] 4888 4136 3523 6564 17632 14595 30817 18337 3672 2068 ...
##  $ 고령자    : int [1:25] 65060 56161 56530 76032 70046 43953 58794 34170 74243 53488 ...
##  $ 세대      : int [1:25] 231612 177407 142533 254257 255352 160798 171570 106066 217619 137378 ...
##  $ 외국인비율: num [1:25] 0.871 0.939 1.074 1.079 3.385 ...
##  $ 고령자비율: num [1:25] 11.6 12.8 17.2 12.5 13.4 ...
##  $ cctv2017  : int [1:25] 4773 1494 946 1363 3314 1235 2741 1104 1750 787 ...
# 5대범죄합계, 범죄발생율(범죄/인구 10만명)과 범죄검거율(검거/발생) 변수 생성 
seoul_crime_pop_cctv <- seoul_crime_pop_cctv %>% 
  mutate(주요범죄발생 = 강간발생 + 강도발생 + 살인발생 + 절도발생 + 폭력발생,
         주요범죄검거 = 강간검거 + 강도검거 + 살인검거 + 절도검거 + 폭력검거,
         주요범죄율 = 주요범죄발생 / 인구 * 100000,
         주요범죄검거율 = 주요범죄검거 / 주요범죄발생,
         강간범죄율 = 강간발생 / 인구 * 100000,
         강간검거율 = 강간검거 / 강간발생,
         강도범죄율 = 강도발생 / 인구 * 100000,
         강도검거율 = 강도검거 / 강도발생,
         살인범죄율 = 살인발생 / 인구 * 100000,
         살인검거율 = 살인검거 / 살인발생,
         절도범죄율 = 절도발생 / 인구 * 100000,
         절도검거율 = 절도검거 / 절도발생,
         폭력범죄율 = 폭력발생 / 인구 * 100000,
         폭력검거율 = 폭력검거 / 폭력발생)
# 데이터 사본 만들기
seoul <- seoul_crime_pop_cctv
str(seoul)
## tibble [25 x 33] (S3: tbl_df/tbl/data.frame)
##  $ 자치구        : chr [1:25] "강남구" "강동구" "강북구" "강서구" ...
##  $ 강간검거      : int [1:25] 496 169 153 253 323 208 181 212 155 115 ...
##  $ 강간발생      : int [1:25] 607 172 208 316 379 261 328 240 180 104 ...
##  $ 강도검거      : int [1:25] 24 12 5 6 6 8 6 5 7 3 ...
##  $ 강도발생      : int [1:25] 20 10 7 4 7 13 8 5 9 3 ...
##  $ 살인검거      : int [1:25] 7 6 8 11 7 5 8 5 4 1 ...
##  $ 살인발생      : int [1:25] 7 5 8 11 8 6 7 5 4 1 ...
##  $ 절도검거      : int [1:25] 1383 949 635 1113 1152 1168 869 674 757 417 ...
##  $ 절도발생      : int [1:25] 3130 1645 1014 1888 1979 2220 1725 1141 1538 633 ...
##  $ 폭력검거      : int [1:25] 3411 2109 2023 2544 2666 1900 2344 1676 2124 1116 ...
##  $ 폭력발생      : int [1:25] 3956 2429 2156 2916 3152 2146 2827 1874 2478 1258 ...
##  $ 인구          : int [1:25] 561052 440359 328002 608255 520929 372298 441559 253491 558075 346234 ...
##  $ 한국인        : int [1:25] 556164 436223 324479 601691 503297 357703 410742 235154 554403 344166 ...
##  $ 외국인        : int [1:25] 4888 4136 3523 6564 17632 14595 30817 18337 3672 2068 ...
##  $ 고령자        : int [1:25] 65060 56161 56530 76032 70046 43953 58794 34170 74243 53488 ...
##  $ 세대          : int [1:25] 231612 177407 142533 254257 255352 160798 171570 106066 217619 137378 ...
##  $ 외국인비율    : num [1:25] 0.871 0.939 1.074 1.079 3.385 ...
##  $ 고령자비율    : num [1:25] 11.6 12.8 17.2 12.5 13.4 ...
##  $ cctv2017      : int [1:25] 4773 1494 946 1363 3314 1235 2741 1104 1750 787 ...
##  $ 주요범죄발생  : int [1:25] 7720 4261 3393 5135 5525 4646 4895 3265 4209 1999 ...
##  $ 주요범죄검거  : int [1:25] 5321 3245 2824 3927 4154 3289 3408 2572 3047 1652 ...
##  $ 주요범죄율    : num [1:25] 1376 968 1034 844 1061 ...
##  $ 주요범죄검거율: num [1:25] 0.689 0.762 0.832 0.765 0.752 ...
##  $ 강간범죄율    : num [1:25] 108.2 39.1 63.4 52 72.8 ...
##  $ 강간검거율    : num [1:25] 0.817 0.983 0.736 0.801 0.852 ...
##  $ 강도범죄율    : num [1:25] 3.565 2.271 2.134 0.658 1.344 ...
##  $ 강도검거율    : num [1:25] 1.2 1.2 0.714 1.5 0.857 ...
##  $ 살인범죄율    : num [1:25] 1.25 1.14 2.44 1.81 1.54 ...
##  $ 살인검거율    : num [1:25] 1 1.2 1 1 0.875 ...
##  $ 절도범죄율    : num [1:25] 558 374 309 310 380 ...
##  $ 절도검거율    : num [1:25] 0.442 0.577 0.626 0.59 0.582 ...
##  $ 폭력범죄율    : num [1:25] 705 552 657 479 605 ...
##  $ 폭력검거율    : num [1:25] 0.862 0.868 0.938 0.872 0.846 ...

데이터 탐색 및 시각화 하기

서울시 범죄 데이터 탐색 질문 (2017년 기준)

  • 주요범죄 발생건수가 높은 구(낮은 구)는?
  • 주요범죄 발생율이 높은 구(낮은 구)는?
  • 주요범죄 검거율이 높은 구(낮은 구)는?
  • 각 범죄의 발생율이 높은 구(낮은 구)는?
  • 각 범죄의 검거율이 높은 구(낮은 구)는?
  • 각 범죄 발생율의 상관관계는?
  • 각 범죄 검거율의 상관관계는?
  • 주요 범죄 발생건수와 발생율의 상관관계는?
  • 인구와 주요범죄 발생건수의 상관관계는?
  • 인구와 주요범죄 발생율의 상관관계는?
  • 죄종별 인구와 범죄발생율의 상관관계는?
  • CCTV와 주요범죄 발생건수의 상관관계는?
  • CCTV와 주요범죄율의 상관관계는?
  • 죄종별 CCTV와 범죄율의 상관관계는?
  • CCTV와 주요범죄 검거율의 상관관계는?
  • 죄종별 CCTV와 주요범죄 검거율의 상관관계는?
  • 외국인 비율과 주요범죄율의 상관관계는?
  • 죄종별 외국인 비율과 범죄율의 상관관계는?
  • 고령자 비율과 주요범죄율의 상관관계는?
  • 죄종별 고령자 비율과 범죄율의 상관관계는?

주요범죄 발생건수가 높은 구(낮은 구)는?

g1 <- seoul %>% 
  mutate(자치구 = fct_reorder(자치구, 주요범죄발생)) %>% 
  ggplot(aes(자치구, 주요범죄발생)) +
  geom_col(fill = "skyblue") +
  coord_flip() +
  labs(title = "서울시 자치구별 주요범죄 발생건수", x = "자치구", y = "발생건수") +
  theme_light()
print(g1)

주요범죄 발생율이 높은 구(낮은 구)는?

g2 <- seoul %>% 
  mutate(자치구 = fct_reorder(자치구, 주요범죄율)) %>% 
  ggplot(aes(자치구, 주요범죄율)) +
  geom_col(fill = "steelblue") +
  coord_flip() +
  labs(title = "서울시 자치구별 주요범죄율", x = "자치구", y = "범죄율") +
  theme_light()
print(g2)

자치구별 주요범죄 발생건수와 발생율 비교

grid.arrange(g1, g2, nrow=1, ncol=2)

주요범죄 검거율이 높은 구(낮은 구)는?

g3 <- seoul %>% 
  mutate(자치구 = fct_reorder(자치구, 주요범죄검거율)) %>% 
  ggplot(aes(자치구, 주요범죄검거율)) +
  geom_segment(aes(xend=자치구, yend=0)) +
  geom_point(size=3, color="orange") +
  coord_flip() +
  labs(title = "서울시 자치구별 주요범죄 검거율", x = "자치구", y = "검거율") +
  theme_light()
print(g3)

자치구별 주요범죄 발생율과 검거율 비교

grid.arrange(g2, g3, nrow=1, ncol=2)

각 범죄의 발생율이 높은 구(낮은 구)는?

# 죄종별 범죄율의 변수명 리스트
offense_list <- c("강간범죄율", "강도범죄율", "살인범죄율", "절도범죄율", "폭력범죄율")
# 막대 그래프 
seoul %>% 
  select(자치구, offense_list) %>% 
  gather(key = "죄종", value = "범죄율", offense_list) %>% 
  ggplot(aes(x = 자치구, y = 범죄율, fill = 죄종)) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~ 죄종, scales = "free") +
  coord_flip() +
  labs(title = "서울시 자치구별 주요범죄 발생율", x = NULL, y = NULL) +
  theme_test()
## Note: Using an external vector in selections is ambiguous.
## i Use `all_of(offense_list)` instead of `offense_list` to silence this message.
## i See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
## This message is displayed once per session.

# 히트맵
seoul %>% 
  select(자치구, offense_list) %>% 
  gather(key = "죄종", value = "범죄율", offense_list) %>%
  ggplot(aes(x = 죄종, y = 자치구)) +
  geom_tile(aes(fill = 범죄율), show.legend = FALSE) +
  scale_fill_gradient(low="white", high="purple3") +
  geom_text(aes(label = format(범죄율, digits = 4))) +
  labs(title = "서울시 자치구별 주요범죄 발생율", x = NULL, y = NULL) +
  theme_minimal()

각 범죄의 검거율이 높은 구(낮은 구)는?

# 죄종별 검거율의 변수명 리스트
arrest_list <- c("강간검거율", "강도검거율", "살인검거율", "절도검거율", "폭력검거율")
# 막대그래프
seoul %>% 
  select(자치구, arrest_list) %>% 
  gather(key = "죄종", value = "검거율", arrest_list) %>% 
  ggplot(aes(x = 자치구, y = 검거율, fill = 죄종)) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~ 죄종, scales = "free") +
  coord_flip() +
  labs(title = "서울시 자치구별 주요범죄 검거율", x = NULL, y = NULL) +
  theme_test()
## Note: Using an external vector in selections is ambiguous.
## i Use `all_of(arrest_list)` instead of `arrest_list` to silence this message.
## i See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
## This message is displayed once per session.

# 히트맵
seoul %>% 
  select(자치구, arrest_list) %>% 
  gather(key = "죄종", value = "검거율", arrest_list) %>% 
  ggplot(aes(x = 죄종, y = 자치구)) +
  geom_tile(aes(fill = 검거율), show.legend = FALSE) +
  scale_fill_gradient(low="white", high="purple3") +
  geom_text(aes(label = format(검거율, digits = 4))) +
  labs(title = "서울시 자치구별 주요범죄 검거율", x = NULL, y = NULL) +
  theme_minimal()

각 범죄 발생율의 상관관계는?

# 변수간 상관계수 
seoul %>% 
  select(offense_list) %>% 
  ggcorr(label=TRUE, size = 5)

# 변수간 상관관계 산점도 및 상관계수
seoul %>% 
  select(offense_list) %>% 
  ggscatmat(alpha = 0.7)

각 범죄 검거율의 상관관계는?

seoul %>% 
  select(arrest_list) %>% 
  ggcorr(label=TRUE, size = 5)

seoul %>% 
  select(arrest_list) %>% 
  ggscatmat(alpha = 0.7)

주요범죄 발생건수와 주요범죄 발생율의 상관관계는?

seoul %>% 
  ggplot(aes(x = 주요범죄발생, y = 주요범죄율)) +
  geom_point(color = "deepskyblue", size = 3) +
  geom_text(aes(label = 자치구, vjust = -0.5, hjust = 0.5)) +
  labs(title = "서울시 주요범죄 발생건수와 주요범죄율") +
  annotate("text", x = 7000, y = 3000, size = 5,
           label = paste("r ==", round(cor(seoul$주요범죄발생, seoul$주요범죄율),2)), 
           parse = TRUE) +
  theme_test()

인구와 주요범죄 발생건수의 상관관계는?

seoul %>% 
  ggplot(aes(x = 인구, y = 주요범죄발생)) +
  geom_point(color = "deepskyblue", size = 3) +
  geom_text(aes(label = 자치구, vjust = -1, hjust = 0.5)) +
  labs(title = "서울시 인구과 주요범죄 발생건수") +
  annotate("text", x = 200000, y = 7000, size = 5,
           label = paste("r ==", round(cor(seoul$인구, seoul$주요범죄발생),2)), 
           parse = TRUE) +
  theme_test()

인구와 주요범죄 발생율의 상관관계는?

seoul %>% 
  ggplot(aes(x = 인구, y = 주요범죄율)) +
  geom_point(color = "deepskyblue", size = 3) +
  geom_text(aes(label = 자치구, vjust = -1, hjust = 0.5)) +
  labs(title = "서울시 인구과 주요범죄율") +
  annotate("text", x = 600000, y = 3000, size = 5,
           label = paste("r ==", round(cor(seoul$인구, seoul$주요범죄율),2)), 
           parse = TRUE) +
  theme_test()

죄종별 인구와 범죄발생율의 상관관계는?

seoul %>% 
  select(자치구, 인구, offense_list) %>% 
  gather(key = "죄종", value = "범죄율", offense_list) %>% 
  ggplot(aes(x = 인구, y = 범죄율)) +
  geom_point(color = "deepskyblue", size = 2) +
  facet_wrap(~ 죄종, scales = "free") +
  geom_text(aes(label = 자치구, vjust = 0, hjust = -0.3), check_overlap = TRUE) +
  labs(title = "서울시 인구과 죄종별 범죄율") +
  theme_test()

CCTV와 주요범죄 발생건수의 상관관계는?

seoul %>% 
  ggplot(aes(x = cctv2017, y = 주요범죄발생)) +
  geom_point(color = "deepskyblue", size = 3) +
  geom_text(aes(label = 자치구, vjust = -1, hjust = 0.5)) +
  labs(title = "서울시 CCTV와 주요범죄 발생건수") +
  annotate("text", x = 3000, y = 7000, size = 5,
           label = paste("r ==", round(cor(seoul$cctv2017, seoul$주요범죄발생),2)), 
           parse = TRUE) +
  theme_test()

CCTV와 주요범죄율의 상관관계는?

seoul %>% 
  ggplot(aes(x = cctv2017, y = 주요범죄율)) +
  geom_point(color = "deepskyblue", size = 3) +
  geom_text(aes(label = 자치구, vjust = -1, hjust = 0.5)) +
  labs(title = "서울시 CCTV와 주요범죄율") +
  annotate("text", x = 3000, y = 3000, size = 5,
           label = paste("r ==", round(cor(seoul$cctv2017, seoul$주요범죄율),2)), 
           parse = TRUE) +
  theme_test()

죄종별 CCTV와 범죄율의 상관관계는?

seoul %>% 
  select(자치구, cctv2017, offense_list) %>% 
  gather(key = "죄종", value = "범죄율", offense_list) %>% 
  ggplot(aes(x = cctv2017, y = 범죄율)) +
  geom_point(color = "deepskyblue", size = 2) +
  facet_wrap(~ 죄종, scales = "free") +
  geom_text(aes(label = 자치구, vjust = 0, hjust = -0.3), check_overlap = TRUE) +
  labs(title = "서울시 CCTV와 죄종별 범죄율") +
  theme_test()

CCTV와 주요범죄 검거율의 상관관계는?

seoul %>% 
  ggplot(aes(x = cctv2017, y = 주요범죄검거율)) +
  geom_point(color = "deepskyblue", size = 3) +
  geom_text(aes(label = 자치구, vjust = -1, hjust = 0.5)) +
  labs(title = "서울시 CCTV와 주요범죄 검거율") +
  annotate("text", x = 3000, y = 0.8, size = 5,
           label = paste("r ==", round(cor(seoul$cctv2017, seoul$주요범죄검거율),2)), 
           parse = TRUE) +
  theme_test()

죄종별 CCTV와 주요범죄 검거율의 상관관계는?

seoul %>% 
  select(자치구, cctv2017, arrest_list) %>% 
  gather(key = "죄종", value = "검거율", arrest_list) %>% 
  ggplot(aes(x = cctv2017, y = 검거율)) +
  geom_point(color = "deepskyblue", size = 2) +
  facet_wrap(~ 죄종, scales = "free") +
  geom_text(aes(label = 자치구, vjust = 0, hjust = -0.3), check_overlap = TRUE) +
  labs(title = "서울시 CCTV와 죄종별 검거율") +
  theme_test()

외국인 비율과 주요범죄율의 상관관계는?

seoul %>% 
  ggplot(aes(x = 외국인비율, y = 주요범죄율)) +
  geom_point(color = "deepskyblue", size = 3) +
  geom_text(aes(label = 자치구, vjust = -1, hjust = 0.5)) +
  geom_smooth(method = lm, color = "deeppink") +
  labs(title = "서울시 외국인비율과 주요범죄율") +
  annotate("text", x = 8, y = 3000, size = 5,
           label = paste("r ==", round(cor(seoul$외국인비율, seoul$주요범죄율),2)), 
           parse = TRUE) +
  theme_test()
## `geom_smooth()` using formula 'y ~ x'

죄종별 외국인 비율과 범죄율의 상관관계는?

seoul %>% 
  select(자치구, 외국인비율, offense_list) %>% 
  gather(key = "죄종", value = "범죄율", offense_list) %>% 
  ggplot(aes(x = 외국인비율, y = 범죄율)) +
  geom_point(color = "deepskyblue", size = 2) +
  facet_wrap(~ 죄종, scales = "free") +
  geom_text(aes(label = 자치구, vjust = 0, hjust = -0.3), check_overlap = TRUE) +
  geom_smooth(method = lm, color = "deeppink") +
  labs(title = "서울시 외국인비율과 죄종별 범죄율") +
  theme_test()
## `geom_smooth()` using formula 'y ~ x'

고령자 비율과 주요범죄율의 상관관계는?

seoul %>% 
  ggplot(aes(x = 고령자비율, y = 주요범죄율)) +
  geom_point(color = "deepskyblue", size = 3) +
  geom_text(aes(label = 자치구, vjust = -1, hjust = 0.5)) +
  geom_smooth(method = lm, color = "deeppink") +
  labs(title = "서울시 고령자비율과 주요범죄율") +
  annotate("text", x = 17, y = 3000, size = 5,
           label = paste("r ==", round(cor(seoul$고령자비율, seoul$주요범죄율),2)), 
           parse = TRUE) +
  theme_test()
## `geom_smooth()` using formula 'y ~ x'

죄종별 고령자 비율과 범죄율의 상관관계는?

seoul %>% 
  select(자치구, 고령자비율, offense_list) %>% 
  gather(key = "죄종", value = "범죄율", offense_list) %>% 
  ggplot(aes(x = 고령자비율, y = 범죄율)) +
  geom_point(color = "deepskyblue", size = 2) +
  facet_wrap(~ 죄종, scales = "free") +
  geom_text(aes(label = 자치구, vjust = 0, hjust = -0.3), check_overlap = TRUE) +
  geom_smooth(method = lm, color = "deeppink") +
  labs(title = "서울시 고령자비율과 죄종별 범죄율") +
  theme_test()
## `geom_smooth()` using formula 'y ~ x'

참고 : 민형기(2017)의 ’파이썬으로 데이터 주무르기’를 참고하여 R 언어로 분석