Post List

2019년 1월 25일 금요일

R을 이용한 데이터로 투자하기 - (2) 데이터 정리 및 변형하기



data science hadley에 대한 이미지 검색결과

지난 시간에 Import, 즉
크롤링을 통한 데이터 수집과정에 대해 살펴보았다면,

이번에는 Tidy와 Transform 즉
데이터 정리 및 변형하기에 대해 알아보도록 하겠습니다.


데이터 가공에는 R의 기본함수를 사용해도 되지만,
데이터 과학에서 가장 애용되는 dplyr 패키지를 사용할 경우
매우 편리하면서도 빠르게 데이터를 정리할 수 있습니다.

따라서 해당 글에서는 dplyr 패키지의 대표적인 함수를 이용하여
금융 데이터를 정리하는 예시들을 살펴보도록 하겠습니다.

dplyr 패키지의 더욱 상세한 내용은
헤들리 위컴의 'R을 활용한 데이터과학'을 살펴보시길 권합니다.




data_sector = read.csv('data_sector.csv', row.names = 1, stringsAsFactors = FALSE)
data_value = read.csv('data_value.csv', row.names = 1, stringsAsFactors = FALSE)


먼저 지난시간 크롤링을 통해 다운로드 받은 csv 파일들을 읽어오도록 합니다.

readr 패키지의 read_csv() 함수를 이용하는 것이 더욱 효과적이지만,
한글의 인코딩이 계속 깨지는 문제로 인해
기본 함수인 read.csv()를 이용하도록 하겠습니다.

row.names=1 를 통해 첫번째 행을 행이름으로,
stringsAsFactors = FALSE 를 통해
데이터가 팩터 형태로 변형되는 것을 막아줍니다.


> head(data_sector)
 시장구분 종목코드         종목명 산업분류 시가총액.원.
1   코스피   030720       동원수산  어업 41884245000
2   코스피   007160       사조산업  어업 249250000000
3   코스피   006040       동원산업  어업 682729600000
4   코스피   004970       신라교역  어업 206400000000
5   코스피   003580 넥스트사이언스     광업 137311128100
6   코스피   280360       롯데제과 음식료품 635574402000
> head(data_value)
 종목코드    PER PBR 배당수익률
1   016670  34.29 1.01       0.00
2   043090 319.29 6.48       0.00
3   044180      - 0.97       0.00
4   051160      - 6.52       0.00
5   068240  55.99 2.23       0.31
6   114120      - 0.41       0.00

> dim(data_sector)
[1] 2227    5
> dim(data_value)
[1] 2187    4

두 데이터의 행렬 갯수를 확인해보면,
섹터 데이터는 행이 2227,
밸류 데이터는 행이 2187개로

섹터 데이터가 40개 종목이 더 많습니다.
이에 대해서는 뒤에서 자세히 다루도록 하겠습니다.


library(dplyr)

# join
data_market.left = left_join(data_sector, data_value, by = '종목코드')
data_market.inner = inner_join(data_sector, data_value, by = '종목코드')

dplyr 패키지를 연 후, left_join()inner_join() 함수를 이용해
두개 데이터를 합쳐보도록 하겠습니다.

by는 데이터를 합칠 기준을 의미하며,
'종목코드'를 기준으로 데이터를 합치도록 합니다.

그렇다면 두 join은 어떠한 차이가 있을까요?


left_join inner_join에 대한 이미지 검색결과



sql을 해보신 분이라면 join의 차이에 대해 잘 알것입니다.
먼저 left_join()은 왼쪽의 x를 기준으로 데이터를 맞추며,
x에는 있지만 y에는 없는 데이터는 NA로 표시됩니다.

반면 inner_join()은 교집합에 해당하는 부분으로 데이터를 맞추며,
x와 y 두곳 모두에 존재하는 데이터를 합칩니다.

> dim(data_market.left)
[1] 2227    8
> dim(data_market.inner)
[1] 2187    8

따라서 두 조인의 결과를 확인해보면
left_join()data_sector를 기준으로 데이터를 합쳤으므로,
해당 데이터와 행의 갯수가 같습니다. (2227개)

그러나 inner_join()은 교집합을 기준으로 데이터를 합쳤으므로,
데이터가 더 작은 data_value와 행의 갯수가 같습니다. (2187개)

그렇다면 과연 이 40개 종목의 차이는 무엇일까요?
여집합을 뜻하는 anti_join()을 통해 확인이 가능합니다.


> anti_join(data_sector, data_value, by = '종목코드')$종목명
[1] "엘브이엠씨홀딩스"   "한국패러랠"         "한국ANKOR유전"      "맵스리얼티1"       
[5] "맥쿼리인프라"       "하나니켈2호"        "하나니켈1호"        "베트남개발1"       
[9] "신한알파리츠"       "이리츠코크렙"       "모두투어리츠"       "하이골드12호"      
[13] "하이골드8호"        "바다로19호"         "하이골드3호"        "케이탑리츠"        
[17] "트러스제7호"        "에이리츠"           "동북아13호"         "동북아12호"        
[21] "컬러레이"           "JTC"                "뉴프라이드"         "윙입푸드"          
[25] "글로벌에스엠"       "크리스탈신소재"     "씨케이에이치"       "차이나그레이트"    
[29] "골든센츄리"         "오가닉티코스메틱"   "GRT"                "로스웰"            
[33] "헝셩그룹"           "이스트아시아홀딩스" "에스앤씨엔진그룹"   "차이나하오란"      
[37] "SBI핀테크솔루션즈"  "잉글우드랩"         "코오롱티슈진"       "엑세스바이오"   

data_sector에는 존재하지만
data_value에는 존재하지 않는 데이터의 종목명을 살펴보면

선박펀드, 광물펀드, 해외종목
일반적이지 않은 종목들이 포함되어 있습니다.

이러한 종목은 제외하는 것이 일반적이므로,
inner_join()을 이용한 데이터를 사용하도록 하겠습니다.


data_market = inner_join(data_sector, data_value, by = '종목코드')
rm(data_market.inner, data_market.left)

data_market에 해당 결과를 저장해주며,
rm() 함수를 이용하여 data_market.inner, data_market.left 데이터를
삭제해주도록 합니다.

# glimpse
glimpse(data_market)

Observations: 2,187
Variables: 8
$ 시장구분     <chr> "코스피", "코스피", "코스피", "코스피", "코스피", "코스피", "코스피", "코스...
$ 종목코드     <chr> "030720", "007160", "006040", "004970", "003580", "2...
$ 종목명       <chr> "동원수산", "사조산업", "동원산업", "신라교역", "넥스트사이언스", "롯데제과", ...
$ 산업분류     <chr> "어업", "어업", "어업", "어업", "광업", "음식료품", "음식료품", "음식료품"...
$ 시가총액.원. 4.188425e+10, 2.492500e+11, 6.827296e+11, 2.064000e+1...
$ PER          <chr> "6.83", "5.63", "4.09", "7.79", "-", "313.28", "...
$ PBR          <chr> "0.96", "0.65", "0.75", "0.43", "1.88", "0.77", ...
$ 배당수익률   0.00, 0.40, 1.97, 3.88, 0.00, 0.19, 0.50, 1.23, 3.32,...

glimpse() 함수는 데이터를 대략 살펴보는 함수이며,
기본함수인 str()과 그 역할이 비슷합니다.

names(data_market)
[1] "시장구분"     "종목코드"     "종목명"       "산업분류"    
[5] "시가총액.원." "PER"          "PBR"          "배당수익률"


먼저 names() 함수를 통해 열이름을 살펴보면
시가총액.원 으로 된 이름이 있으며,
이를 시가총액 으로 변경하고자 합니다.

열 이름 변경은 rename() 함수를 사용하면 됩니다.

data_market = data_market %>%
 rename(시가총액 = 시가총액.원.)
names(data_market)

[1] "시장구분"   "종목코드"   "종목명"     "산업분류"   "시가총액"  
[6] "PER"        "PBR"        "배당수익률"

rename(A = B)  형식을 사용하며,
A는 변경하고자 하는 이름, B는 현재 이름을 입력하면 됩니다.
이름이 변경된 것을 확인할 수 있습니다.

# distinct
data_market %>%
 distinct(산업분류) %>% c()
$산업분류
[1] "어업"           "광업" "음식료품"       "섬유의복"
[5] "종이목재"       "화학" "의약품"         "비금속광물"
[9] "철강금속"       "기계" "전기전자"       "의료정밀"
[13] "운수장비"       "기타제조" "유통업"         "전기가스업"
[17] "건설업"         "운수창고업" "통신업"       "금융업"
[21] "서비스업"       "기타서비스" "농림업"        "전기,가스,수도"
[25] "건설"           "유통" "숙박·음식"     "운송"
[29] "금융"           "오락·문화" "통신방송서비스" "IT S/W & SVC"  
[33] "IT H/W"         "음식료·담배" "섬유·의류" "종이·목재"    
[37] "출판·매체복제" "제약"           "비금속" "금속"
[41] "기계·장비"     "일반전기전자" "의료·정밀기기" "운송장비·부품"
[45] "기타 제조"    

distinct() 함수는 중복값을 제거하고 고유값만을 보여주며,
기본 함수인 unique()와 동일한 기능을 합니다.

총 45개의 산업분류가 존재함이 확인됩니다.

# select
data_market %>%
 select(종목명) %>% head()
        종목명
1       동원수산
2       사조산업
3       동원산업
4       신라교역
5 넥스트사이언스
6       롯데제과

select()는 원하는 열을 선택하는 함수입니다.
data_market 중 종목명 부분만 선택이 됨이 확인됩니다.


data_market %>%
 select(종목명, PER, PBR) %>% head()

         종목명 PER  PBR
1       동원수산 6.83 0.96
2       사조산업 5.63 0.65
3       동원산업 4.09 0.75
4       신라교역 7.79 0.43
5 넥스트사이언스      - 1.88
6       롯데제과 313.28 0.77

한번에 여러 열을 선택할 수도 있습니다.


data_market %>%
 select(starts_with('시')) %>% head()
시장구분     시가총액
1   코스피  41884245000
2   코스피 249250000000
3   코스피 682729600000
4   코스피 206400000000
5   코스피 137311128100
6   코스피 635574402000

data_market %>%
 select(ends_with('R')) %>% head()

    PER PBR
1   6.83 0.96
2   5.63 0.65
3   4.09 0.75
4   7.79 0.43
5      - 1.88
6 313.28 0.77

data_market %>%
 select(contains('종목')) %>% head()

 종목코드         종목명
1   030720       동원수산
2   007160       사조산업
3   006040       동원산업
4   004970       신라교역
5   003580 넥스트사이언스
6   280360       롯데제과


select() 함수에는 다양한 응용버전도 존재합니다.

starts_with()를 입력할 경우 원하는 문자로 시작하는 열을,
ends_with()를 입력할 경우 원하는 문자로 끝나는 열을,
contains()를 입력할 경우 원하는 문자가 포함된 열을
선택할 수 있습니다.


data_market = data_market %>%
 mutate(PBR = as.numeric(PBR),
        PER = as.numeric(PER),
        ROE = PBR / PER,
        ROE = round(ROE, 4),
        style = ifelse(PBR < median(PBR, na.rm = TRUE),
                       'value', 'growth')
        )


mutate() 함수는 데이터를 변형 후 저장합니다.

먼저 문자 형태인 PBR과 PER 열을 as.numeric() 함수를 이용하여
숫자 형태로 변형해줍니다.

또한 ROE는 PBR / PER로 나타낼 수 있으므로,
이를 ROE 열에 새로 저장해주며,
round() 함수를 이용하여 반올림을 해주도록 합니다.

또한 style 열에는 ifelse() 함수를 이용하여
PBR이 median 값보다 작을 경우 value를,
그렇지 않을 경우에는 growth를 입력합니다.


data_market %>% head()

 시장구분 종목코드         종목명 산업분류 시가총액   PER PBR
1   코스피   030720       동원수산  어업 41884245000   6.83 0.96
2   코스피   007160       사조산업  어업 249250000000   5.63 0.65
3   코스피   006040       동원산업  어업 682729600000   4.09 0.75
4   코스피   004970       신라교역  어업 206400000000   7.79 0.43
5   코스피   003580 넥스트사이언스     광업 137311128100     NA 1.88
6   코스피   280360       롯데제과 음식료품 635574402000 313.28 0.77
 배당수익률    ROE style
1       0.00 0.1406  value
2       0.40 0.1155  value
3       1.97 0.1834  value
4       3.88 0.0552  value
5       0.00     NA growth
6       0.19 0.0025  value


데이터를 확인해보면 mutate() 함수가 잘 적용되어 있습니다.


data_market_ROE = data_market %>%
 transmute(ROE = PBR / PER)   
data_market_ROE %>% head()

         ROE
1 0.140556369
2 0.115452931
3 0.183374083
4 0.055198973
5          NA
6 0.002457865

mutate() 함수와 비슷한 함수로 transmute() 함수가 있습니다.

mutate() 함수는 기존 데이터가 유지되는 반면,
transmute() 함수는 새로 생성된 데이터만이 저장됩니다.


# filter
data_market %>%
 select(종목명, PBR) %>%
 filter(PBR < 1) %>% head()

   종목명 PBR
1 동원수산 0.96
2 사조산업 0.65
3 동원산업 0.75
4 신라교역 0.43
5 롯데제과 0.77
6 사조오양 0.62

filter() 함수는 조건에 해당하는 행을 찾아주는 함수입니다.
먼저 종목명과 PBR 열을 선택해준 후,
PBR이 1 미만인 데이터를 필터링 해주면
이에 해당하는 결과를 보여줍니다.


data_market %>%
 select(종목명, PER, PBR, ROE) %>%
 filter(PBR < 1 & PER < 20 & ROE > 0.1 ) %>% head()

   종목명 PER  PBR ROE
1 동원수산 6.83 0.96 0.1406
2 사조산업 5.63 0.65 0.1155
3 동원산업 4.09 0.75 0.1834
4 사조오양 3.82 0.62 0.1623
5     선진 3.66 0.84 0.2295
6   팜스코 7.00 0.90 0.1286

조건을 여러개 입력할 수도 있습니다.

PBR이 1 미만,
PER가 20 미만,
ROE가 10% 이상을 조건으로 주면

이에 해당하는 종목들을 보여줍니다.


data_market %>%
 filter(substr(종목명, nchar(종목명), nchar(종목명)) %in% c('우') |
          substr(종목명, nchar(종목명) - 1, nchar(종목명)) %in% c('우B', '우C') |
          grepl('스팩', 종목명)) %>%
 select(종목명) %>% c()

$종목명
 [1] "크라운제과우"        "삼양사우"            "하이트진로2우B"      "대한제당3우B"       
 [5] "CJ씨푸드1우"         "CJ제일제당 우"       "롯데칠성우"          "서울식품우"         
 [9] "남양유업우"          "대한제당우"          "대상우"              "신원우"             
[13] "BYC우"               "깨끗한나라우"        "SK케미칼우"          "한화3우B"           
[17] "동원시스템즈우"      "코오롱인더우"        "LG하우시스우"        "노루페인트우"       
[21] "아모레퍼시픽우"      "LG화학우"            "LG생활건강우"        "금호석유우"         
[25] "S-Oil우"             "한화케미칼우"        "덕성우"              "NPC우"              
[29] "넥센타이어1우B"      "한화우"              "신풍제약우"          "일양약품우"         
[33] "JW중외제약2우B"      "JW중외제약우"        "유유제약2우B"        "유유제약1우"        
[37] "유한양행우"          "동양3우B"            "동양2우B"            "동양우"             
[41] "성신양회3우B"        "성신양회2우B"        "성신양회우"          "쌍용양회우"         
[45] "금강공업우"          "동부제철우"          "남선알미우"          "현대비앤지스틸우"   
[49] "계양전기우"          "대덕전자1우"         "코리아써키트2우B"    "DB하이텍1우"        
[53] "LG전자우"            "성문전자우"          "삼성전기우"          "코리아써우"         
[57] "삼성SDI우"           "대원전선우"          "삼성전자우"          "삼성중공우"         
[61] "현대차3우B"          "현대차2우B"          "현대차우"            "태양금속우"         
[65] "삼성물산우B"         "호텔신라우"          "포스코대우"          "SK네트웍스우"       
[69] "진흥기업2우B"        "금호산업우"          "진흥기업우B"         "태영건설우"         
[73] "동부건설우"          "코오롱글로벌우"      "현대건설우"          "대림산업우"         
[77] "세방우"              "대한항공우"          "SK디스커버리우"      "미래에셋대우2우B"   
[81] "롯데지주우"          "한진칼우"            "SK이노베이션우"      "대상홀딩스우"       
[85] "GS우"                "SK우"                "크라운해태홀딩스우"  "넥센우"             
[89] "LG우"                "아모레G우"           "코오롱우"            "CJ우"               
[93] "노루홀딩스우"        "하이트진로홀딩스우"  "삼양홀딩스우"        "대신증권2우B"       
[97] "한국금융지주우"      "미래에셋대우우"      "미래에셋대우"        "NH투자증권우"       
[101] "대신증권우"          "한화투자증권우"      "유안타증권우"        "유화증권우"         
[105] "한양증권우"          "신영증권우"          "SK증권우"            "부국증권우"         
[109] "삼성화재우"          "흥국화재2우B"        "흥국화재우"          "두산2우B"           
[113] "두산우"              "대교우B"             "녹십자홀딩스2우"     "소프트센우"         
[117] "키움제5호스팩"       "엔에이치스팩13호"    "미래에셋대우스팩2호" "신영스팩4호"        
[121] "한국제8호스팩"       "삼성머스트스팩3호"   "대신밸런스제6호스팩" "SK4호스팩"          
[125] "교보8호스팩"         "하나머스트제6호스팩" "DB금융스팩6호"       "IBKS제10호스팩"     
[129] "삼성스팩2호"         "대신밸런스제5호스팩" "IBKS제9호스팩"       "하나금융11호스팩"   
[133] "한국제7호스팩"       "유안타제3호스팩"     "대신밸런스제3호스팩" "한국제6호스팩"      
[137] "동부스팩5호"         "한화에이스스팩4호"   "IBKS제7호스팩"       "신한제4호스팩"      
[141] "하나금융10호스팩"    "엔에이치스팩12호"    "한국제5호스팩"       "하나금융9호스팩"    
[145] "교보7호스팩"         "한화수성스팩"        "IBKS제6호스팩"       "미래에셋대우스팩1호"
[149] "한화에이스스팩3호"   "엔에이치스팩10호"    "케이비제11호스팩"    "대신밸런스제4호스팩"
[153] "신한제3호스팩"       "엔에이치스팩11호"    "IBKS제5호스팩"       "SK3호스팩"          
[157] "케이비제10호스팩"    "한국4호스팩"         "미래에셋제5호스팩"   "연우"               
[161] "대호피앤씨우"        "루트로닉3우C"


filter() 함수를 이용하여
우선주 및 스팩 종목을 제거할 수 있습니다.


1. 종목명 마지막 글자가 '우'
2. 종목명 마지막 글자가 '우B' 나 '우C'
3. 종목명에 '스팩'이 들어가는

종목들을 찾아주면 위와 같습니다.

위의 조건에 해당하지 않은 종목을 찾기 위해,
not(A or B), 즉 not A and not B를 응용하면 다음과 같습니다.


data_market = data_market %>%
 filter(!substr(종목명, nchar(종목명), nchar(종목명)) %in% c('우') &
          !substr(종목명, nchar(종목명) - 1, nchar(종목명)) %in% c('우B', '우C') &
          !grepl('스팩', 종목명))

nrow(data_market)
[1] 2025

종목수가 기존 2187 개에서 162개가 줄어든 2025개가 되었습니다.


# summarize
market_PBR =
 data_market %>%
 summarize(PBR.med = median(PBR, na.rm = TRUE)) %>%
 as.numeric()


summarize() 함수는 원하는 통계값을 계산해주는 함수입니다.
PBR.med 변수에 PBR 열의 median 값들을 저장해주도록 합니다.

market_PBR
[1] 1.08

국내 종목들의 평균(median) PBR은 1.08 정도임이 확인됩니다.


# arrange
data_market %>%
 arrange(PBR) %>%
 select(PBR) %>%
 head(5)

  PBR
1 0.08
2 0.10
3 0.12
4 0.14
5 0.16

data_market %>%
 arrange(desc(ROE)) %>%
 select(ROE) %>%
 head(5)

    ROE
1 9.4286
2 6.0000
3 5.2500
4 3.5263
5 3.4444

arrange() 함수는 데이터를 정렬해주는 역할을 합니다.
기본적으로는 오름차순으로 데이터를 정리하며,
desc()함수를 사용할 경우 내림차순으로 정리합니다.


# mutate + arrange
data_market = data_market %>%
 mutate(시총비중 = 시가총액 / sum(시가총액)) %>%
 arrange(desc(시가총액))

시가총액 비중을 구한 후, 비중 순으로 정리해보도록 하겠습니다.
먼저 mutate() 함수를 통해 시총비중을 구하며,
arrange() 내에 desc() 함수를 통해
시총 비중이 큰 순서부터 내림차순을 정리해주도록 합니다.


data_market %>%
 select(종목명, 시가총액) %>%
 head(10)

            종목명 시가총액
1          삼성전자 2.310306e+14
2        SK하이닉스 4.404414e+13
3          셀트리온 2.791399e+13
4  삼성바이오로직스 2.557277e+13
5            현대차 2.531968e+13
6            LG화학 2.449554e+13
7          SK텔레콤 2.176097e+13
8          한국전력 2.124901e+13
9             POSCO 2.118640e+13
10            NAVER 2.010723e+13

종목명과 시가총액을 뽑아 상위 10종목을 확인해보면
시총 순서대로 정리되었음이 확인됩니다.


data_market %>%
 group_by(시장구분) %>% str()
Classes grouped_df, tbl_df, tbl and 'data.frame': 2025 obs. of  13 variables:
$ 시장구분  : chr  "코스피" "코스피" "코스피" "코스피" ...
$ 종목코드  : chr  "005930" "000660" "068270" "207940" ...
$ 종목명    : chr  "삼성전자" "SK하이닉스" "셀트리온" "삼성바이오로직스" ...
$ 산업분류  : chr  "전기전자" "전기전자" "의약품" "의약품" ...
$ 시가총액  : num 2.31e+14 4.40e+13 2.79e+13 2.56e+13 2.53e+13 ...
$ EPS       : int  5997 15073 3150 NA 14993 25367 36582 2023 34464 5320 ...
$ PER       : num 6.45 4.01 70.63 NA 7.9 ...
$ BPS       : int  28126 46449 19041 60099 242062 206544 220967 111660 501600 28936 ...
$ PBR       : num 1.38 1.3 11.69 6.43 0.49 ...
$ 배당수익률: num  2.2 1.65 0 0 3.38 1.73 3.71 2.39 3.29 0.24 ...
$ ROE       : num 0.214 0.324 0.166 NA 0.062 ...
$ style     : chr  "growth" "growth" "growth" "growth" ...
$ 시총비중  : num 0.1526 0.0291 0.0184 0.0169 0.0167 ...
- attr(*, "vars")= chr "시장구분"
- attr(*, "drop")= logi TRUE
- attr(*, "indices")=List of 2
 ..$ : int  27 51 62 63 67 80 85 91 95 109 ...
 ..$ : int  0 1 2 3 4 5 6 7 8 9 ...
- attr(*, "group_sizes")= int  1259 766
- attr(*, "biggest_group_size")= int 1259
- attr(*, "labels")='data.frame': 2 obs. of  1 variable:
 ..$ 시장구분: chr  "코스닥" "코스피"
 ..- attr(*, "vars")= chr "시장구분"
 ..- attr(*, "drop")= logi TRUE

group_by() 함수는 원하는 기준대로 데이터를 묶는 함수로써,
함수를 사용하는 것만으로는 변화를 알아차리기 힘듭니다.

data_market %>%
 group_by(산업분류) %>%
 summarize(n())

# A tibble: 45 x 2
  산업분류     `n()`
  <chr>        <int>
1 IT H/W         296
2 IT S/W & SVC   138
3 건설            24
4 건설업          31
5 광업             3
6 금속            62
7 금융            43
8 금융업         112
9 기계            41
10 기계·장비       85
# ... with 35 more rows

group_by() 함수를 이용하여 산업분류 별로 그룹화 한 후,
summarize() 함수 내에 n() 함수를 사용하여
각 섹터 별 종목수를 구할 수 있습니다.


data_market %>%
 group_by(시장구분) %>%
 summarize(PBR.mkt = median(PBR, na.rm = TRUE))

# A tibble: 2 x 2
 시장구분 PBR.mkt
 <chr>      
1 코스닥      1.36
2 코스피      0.8

data_market %>%
 group_by(산업분류) %>%
 summarize(PBR.sector = median(PBR, na.rm = TRUE))

# A tibble: 45 x 2
  산업분류     PBR.sector
  <chr>             
1 IT H/W             1.17
2 IT S/W & SVC       1.83
3 건설               0.84
4 건설업             0.8
5 광업               1.88
6 금속               0.79
7 금융               0.88
8 금융업             0.56
9 기계               0.9
10 기계·장비          1.32
# ... with 35 more rows


각 시장별과 섹터별 PBR의 median 값을 구하는 것도 가능합니다.

data_market %>%
 group_by(시장구분, 산업분류) %>%
 summarize(cap = sum(시가총액)) %>%
 mutate(cap = cap / sum(data_market$시가총액),
        cap = round(cap, 5)) %>%
 arrange(desc(cap))

# A tibble: 47 x 3
# Groups:   시장구분 [2]
  시장구분 산업분류    cap
  <chr>    <chr>     
1 코스피   전기전자 0.218
2 코스피   금융업 0.167
3 코스피   화학 0.0836
4 코스피   서비스업 0.0727
5 코스피   운수장비 0.0609
6 코스피   의약품 0.0536
7 코스피   유통업 0.0441
8 코스피   철강금속 0.0286
9 코스닥   IT H/W  0.0257
10 코스피   통신업 0.0249
# ... with 37 more rows


위에서 배웠던 함수들을 활용하여
각 섹터 별 시가총액 비중을 구하도록 하겠습니다.

먼저 group_by() 함수를 이용해
시장과 섹터별로 그룹화를 해줍니다.

그 후, summarize() 함수를 이용하여
각 그룹 별 시가총액의 합을 구해줍니다.
mutate() 함수를 통해 그룹별 시총 / 전체 시총을 계산하여
이를 cap에 저장해 주며,
round() 함수를 이용해 반올림 해주도록 합니다.

마지막으로 arrange()desc() 함수를 이용하여
내림차순으로 정리를 해주면
각 그룹별 시가총액이 높은 순부터 정리됩니다.

결과를 확인해보면 삼성전자가 포함된 코스피-전기전자 비중이
단연 높음이 확인됩니다.





크롤링한 데이터를 바탕으로 데이터 정리 및 변형에 대해
알아보았습니다.

다음에는 마지막으로 시각화 및 모델링,
퀀트를 이용한 종목선택에 대해 알아보도록 하겠습니다.

댓글 없음:

댓글 쓰기