-
Notifications
You must be signed in to change notification settings - Fork 50
/
Copy path07-bind_data.Rmd
262 lines (189 loc) · 10.6 KB
/
07-bind_data.Rmd
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# 데이터 정리하기
```{r echo = FALSE, warning = FALSE, message = FALSE}
library(magrittr)
library(dplyr)
KOR_ticker = read.csv('data/KOR_ticker.csv', row.names = 1)
```
앞 CHAPTER에서는 API와 크롤링을 통해 주가, 재무제표, 가치지표를 수집하는 방법을 배웠습니다. 이번 CHAPTER에서는 각각 csv 파일로 저장된 데이터들을 하나로 합친 후 저장하는 과정을 살펴보겠습니다.
## 주가 정리하기
주가는 data/KOR_price 폴더 내에 티커_price.csv 파일로 저장되어 있습니다. 해당 파일들을 불러온 후 데이터를 묶는 작업을 통해 하나의 파일로 합치는 방법을 알아보겠습니다.
```{r message = FALSE, warning = FALSE, eval = FALSE}
library(stringr)
library(xts)
library(magrittr)
KOR_ticker = read.csv('data/KOR_ticker.csv', row.names = 1)
KOR_ticker$'종목코드' =
str_pad(KOR_ticker$'종목코드', 6, side = c('left'), pad = '0')
price_list = list()
for (i in 1 : nrow(KOR_ticker)) {
name = KOR_ticker[i, '종목코드']
price_list[[i]] =
read.csv(paste0('data/KOR_price/', name,
'_price.csv'),row.names = 1) %>%
as.xts()
}
price_list = do.call(cbind, price_list) %>% na.locf()
colnames(price_list) = KOR_ticker$'종목코드'
```
```{r echo = FALSE}
# 저장된 데이터 불러오기
price_list = read.csv('data/KOR_price.csv')
```
```{r}
head(price_list[, 1:5])
tail(price_list[, 1:5])
```
1. 티커가 저장된 csv 파일을 불러온 후 티커를 6자리로 맞춰줍니다.
2. 빈 리스트인 price_list를 생성합니다.
3. for loop 구문을 이용해 종목별 가격 데이터를 불러온 후 `as.xts()`를 통해 시계열 형태로 데이터를 변경하고 리스트에 저장합니다.
4. `do.call()` 함수를 통해 리스트를 열 형태로 묶습니다.
5. 간혹 결측치가 발생할 수 있으므로, `na.locf()` 함수를 통해 결측치에는 전일 데이터를 사용합니다.
6. 행 이름을 각 종목의 티커로 변경합니다.
해당 작업을 통해 개별 csv 파일로 흩어져 있던 가격 데이터가 하나의 데이터로 묶이게 됩니다.
```{r eval = FALSE}
write.csv(data.frame(price_list), 'data/KOR_price.csv')
```
마지막으로 해당 데이터를 data 폴더에 KOR_price.csv 파일로 저장합니다. 시계열 형태 그대로 저장하면 인덱스가 삭제되므로 데이터 프레임 형태로 변경한 후 저장해야 합니다.
## 재무제표 정리하기
재무제표는 data/KOR_fs 폴더 내 티커_fs.csv 파일로 저장되어 있습니다. 주가는 하나의 열로 이루어져 있어 데이터를 정리하는 것이 간단했지만, 재무제표는 각 종목별 재무 항목이 모두 달라 정리하기 번거롭습니다.
```{r message = FALSE, eval = FALSE}
library(stringr)
library(magrittr)
library(dplyr)
KOR_ticker = read.csv('data/KOR_ticker.csv', row.names = 1)
KOR_ticker$'종목코드' =
str_pad(KOR_ticker$'종목코드', 6, side = c('left'), pad = '0')
data_fs = list()
for (i in 1 : nrow(KOR_ticker)){
name = KOR_ticker[i, '종목코드']
data_fs[[i]] = read.csv(paste0('data/KOR_fs/', name,
'_fs.csv'), row.names = 1)
}
```
```{r eval = FALSE, echo = FALSE}
saveRDS(data_fs, 'data/data_fs.Rds')
```
```{r echo = FALSE}
# 저장된 데이터 불러오기
data_fs = readRDS('data/data_fs.Rds')
```
위와 동일하게 티커 데이터를 읽어옵니다. 이를 바탕으로 종목별 재무제표 데이터를 읽어온 후 리스트에 저장합니다.
```{r}
fs_item = data_fs[[1]] %>% rownames()
length(fs_item)
print(head(fs_item))
```
다음으로 재무제표 항목의 기준을 정해줄 필요가 있습니다. 재무제표 작성 항목은 각 업종별로 상이하므로, 이를 모두 고려하면 지나치게 데이터가 커지게 됩니다. 또한 퀀트 투자에는 일반적이고 공통적인 항목을 주로 사용하므로 대표적인 재무 항목을 정해 이를 기준으로 데이터를 정리해도 충분합니다.
따라서 기준점으로 첫 번째 리스트, 즉 삼성전자의 재무 항목을 선택하며, 총 `r length(fs_item)`개 재무 항목이 있습니다. 해당 기준을 바탕으로 재무제표 데이터를 정리하며, 전체 항목에 대한 정리 이전에 간단한 예시로 첫 번째 항목인 매출액 기준 데이터 정리를 살펴보겠습니다.
```{r}
select_fs = lapply(data_fs, function(x) {
# 해당 항목이 있을시 데이터를 선택
if ( '매출액' %in% rownames(x) ) {
x[which(rownames(x) == '매출액'), ]
# 해당 항목이 존재하지 않을 시, NA로 된 데이터프레임 생성
} else {
data.frame(NA)
}
})
select_fs = bind_rows(select_fs)
print(head(select_fs))
```
먼저 `lapply()` 함수를 이용해 모든 재무 데이터가 들어 있는 data_fs 데이터를 대상으로 함수를 적용합니다. `%in%` 함수를 통해 만일 매출액이라는 항목이 행 이름에 있으면 해당 부분의 데이터를 select_fs 리스트에 저장하고, 해당 항목이 없는 경우 NA로 이루어진 데이터 프레임을 저장합니다.
그 후, dplyr 패키지의 `bind_rows()` 함수를 이용해 리스트 내 데이터들을 행으로 묶어줍니다. `rbind()`에서는 리스트 형태를 테이블로 묶으려면 모든 데이터의 열 개수가 동일해야 하는 반면, `bind_rows()`에서는 열 개수가 다를 경우 나머지 부분을 NA로 처리해 합쳐주는 장점이 있습니다.
합쳐진 데이터를 살펴보면, 먼저 열 이름이 . 혹은 NA.인 부분이 있습니다. 이는 매출액 항목이 없는 종목의 경우 NA 데이터 프레임을 저장해 생긴 결과입니다. 또한 연도가 순서대로 저장되지 않은 경우가 있습니다. 이 두 가지를 고려해 데이터를 클렌징합니다.
``` {r}
select_fs = select_fs[!colnames(select_fs) %in%
c('.', 'NA.')]
select_fs = select_fs[, order(names(select_fs))]
rownames(select_fs) = KOR_ticker[, '종목코드']
print(head(select_fs))
```
1. `!`와 `%in%` 함수를 이용해, 열 이름에 . 혹은 NA.가 들어가지 않은 열만 선택합니다.
2. `order()` 함수를 이용해 열 이름의 연도별 순서를 구한 후 이를 바탕으로 열을 다시 정리합니다.
3. 행 이름을 티커들로 변경합니다.
해당 과정을 통해 전 종목의 매출액 데이터가 연도별로 정리되었습니다. for loop 구문을 이용해 모든 재무 항목에 대한 데이터를 정리하는 방법은 다음과 같습니다.
```{r eval = FALSE}
fs_list = list()
for (i in 1 : length(fs_item)) {
select_fs = lapply(data_fs, function(x) {
# 해당 항목이 있을시 데이터를 선택
if ( fs_item[i] %in% rownames(x) ) {
x[which(rownames(x) == fs_item[i]), ]
# 해당 항목이 존재하지 않을 시, NA로 된 데이터프레임 생성
} else {
data.frame(NA)
}
})
# 리스트 데이터를 행으로 묶어줌
select_fs = bind_rows(select_fs)
# 열이름이 '.' 혹은 'NA.'인 지점은 삭제 (NA 데이터)
select_fs = select_fs[!colnames(select_fs) %in%
c('.', 'NA.')]
# 연도 순별로 정리
select_fs = select_fs[, order(names(select_fs))]
# 행이름을 티커로 변경
rownames(select_fs) = KOR_ticker[, '종목코드']
# 리스트에 최종 저장
fs_list[[i]] = select_fs
}
# 리스트 이름을 재무 항목으로 변경
names(fs_list) = fs_item
```
위 과정을 거치면 fs_list에 총 `r length(fs_item)`개 리스트가 생성됩니다. 각 리스트에는 해당 재무 항목에 대한 전 종목의 연도별 데이터가 정리되어 있습니다.
```{r eval = FALSE}
saveRDS(fs_list, 'data/KOR_fs.Rds')
```
마지막으로 해당 데이터를 data 폴더 내에 저장합니다. 리스트 형태 그대로 저장하기 위해 `saveRDS()` 함수를 이용해 KOR_fs.Rds 파일로 저장합니다.
Rds 형식은 파일을 더블 클릭한 후 연결 프로그램을 R Studio로 설정해 파일을 불러올 수 있습니다. 혹은 `readRDS()` 함수를 이용해 파일을 읽어올 수도 있습니다.
## 가치지표 정리하기
가치지표는 data/KOR_value 폴더 내 티커_value.csv 파일로 저장되어 있습니다. 재무제표를 정리하는 방법과 거의 동일합니다.
```{r message = FALSE}
library(stringr)
library(magrittr)
library(dplyr)
KOR_ticker = read.csv('data/KOR_ticker.csv', row.names = 1)
KOR_ticker$'종목코드' =
str_pad(KOR_ticker$'종목코드', 6, side = c('left'), pad = '0')
data_value = list()
for (i in 1 : nrow(KOR_ticker)){
name = KOR_ticker[i, '종목코드']
data_value[[i]] =
read.csv(paste0('data/KOR_value/', name,
'_value.csv'), row.names = 1) %>%
t() %>% data.frame()
}
```
먼저 티커에 해당하는 파일을 불러온 후 for loop 구문을 통해 가치지표 데이터를 data_value 리스트에 저장합니다. 단, csv 내에 데이터가 \@ref(tab:valuesample)와 같이 행의 형태로 저장되어 있으므로, t() 함수를 이용해 열의 형태로 바꿔주며, 데이터 프레임 형태로 저장합니다.
```{r valuesample, echo = FALSE}
knitr::kable(
data.frame(
'value' = c('PER', 'PBR', 'PCR', 'PSR'),
'x' = c('Number 1', 'Number 2', 'Number 3', 'Number 4')),
booktabs = TRUE,
align = "c",
caption = '가치지표의 저장 예시'
) %>%
kableExtra::kable_styling(latex_options = c("striped", "hold_position")) %>%
kableExtra::column_spec(1, width = "3cm") %>%
kableExtra::column_spec(2, width = "5cm")
```
```{r}
data_value = bind_rows(data_value)
print(head(data_value))
```
`bind_rows()` 함수를 이용하여 리스트 내 데이터들을 행으로 묶어준 후 데이터를 확인해보면 PER, PBR, PCR, PSR 열 외에 불필요한 NA로 이루어진 열이 존재합니다. 해당 열을 삭제한 후 정리 작업을 하겠습니다.
```{r}
data_value = data_value[colnames(data_value) %in%
c('PER', 'PBR', 'PCR', 'PSR')]
data_value = data_value %>%
mutate_all(list(~na_if(., Inf)))
rownames(data_value) = KOR_ticker[, '종목코드']
print(head(data_value))
```
```{r eval = FALSE}
write.csv(data_value, 'data/KOR_value.csv')
```
1. 열 이름이 가치지표에 해당하는 부분만 선택합니다.
2. 일부 종목은 재무 데이터가 0으로 표기되어 가치지표가 Inf로 계산되는 경우가 있습니다. `mutate_all()` 내에 `na_if()` 함수를 이용해 Inf 데이터를 NA로 변경합니다.
3. 행 이름을 티커들로 변경합니다.
4. data 폴더 내에 KOR_value.csv 파일로 저장합니다.