도매시장 경락 데이터의 이해 - 당근

이번 Post에서 사용하는 데이터는 농림축산식품교육문화정보원에서 수집하여 공공데이터포털을 통해 제공되는 농수축산물 도매시장 상세 경락가격 Open API에서 수집한 데이터로 AWS S3 Agdata Lab 저장소에서 다운로드할 수 있다. 수집 기간은 2015년 1월부터 2018년 7월까지이며(정확히는 2018년 8월 1일) 전국 34개의 농산물 공영도매시장에서 거래된 당근 품목의 모든 데이터가 기록되어 있다.

먼저 csv파일을 읽어와서 dat 데이터로 저장하고 측정치 개수를 확인해보자. 그 결과 558,225개로, 총 43개월 중(2015년 1월 ~ 2018년 7월) 월 20일 도매시장이 개장되었다고 가정했을 때 하루 평균 거래 건수는 649.1건으로 단순화해서 볼 수 있겠으나, 날짜별 거래건수를 합해서 내림차순으로 정렬해서 상위 거래 건수를 확인해보면 거래가 많을 때는 1,000건 이상 있었던 것을 확인할 수 있다.

dat <- read.csv('carrot_2015-2018.csv')
print(paste('number of observation :',nrow(dat)))
## [1] "number of observation : 558225"
dat %>% group_by(date) %>% tally() %>% arrange(desc(n)) %>% head()
## # A tibble: 6 x 2
##       date     n
##      <int> <int>
## 1 20170512  1454
## 2 20170417  1273
## 3 20170120  1102
## 4 20170414  1090
## 5 20180213  1085
## 6 20170428  1061

앞선 포스트와 같이 필요한 변수들을 설정해준 후, histogram을 이용한 분포를 보면, 최대 kg당 약 10만원에 거래된 당근이 있는 것을 확인할 수 있다. 다시 kg당 5,000원 미만으로 필터링하여 histogram을 그려보면 실제 거래가 가장 많이 일어나고 있는 가격 범위는 1,500원 이하인 것을 확인할 수 있다.

gh1 <- ggplot(dat, aes(x = price_per_kg)) + geom_histogram(fill = "red", color = "red", bins = 1000)  
gh2 <- ggplot(dat %>% filter(price_per_kg<=5000), aes(x = price_per_kg)) + geom_histogram(fill = "firebrick2", color = "firebrick2", bins = 1000) 
grid.arrange(gh1, gh2, ncol=1, nrow=2)

아래 표와 같이 price_per_kg을 내림차순으로 정렬하여 상위 30개를 추려보면, 산지가 서울특별시 송파구인 곳이 많은 것을 알 수 있다. prut의 경우 1 이하인 것이 많은 것 또한 확인할 수 있다. 데이터를 들여다보면, 너무 낮거나 높은 price_per_kg값을 가지는 데이터들은 prut값이 일반적이지 않은 것을 볼 수 있다. price_per_kg이 너무 낮은 것들은 대부분 기존의 prut값을 10 또는 100으로 나눠주면 평균 당근 도매가와 비슷한 가격이 나온다. 반대로, price_per_kg이 너무 높은 것들은 prut값에 10 또는 100을 곱해주면 평균 당근 도매가와 비슷한 가격이 나오는 것을 확인할 수 있다. 그래서 이상치의 원인은 잘못된 prut값에 있지 않을까하는 생각을 하게 되었다.

Table 1: kg당 가격 기준 내림차순 데이터 상위 30개
aucCodeName bidTime date grade insname market package price prodname prut qty sanji sanji_wide sanji_city shipment spename unit year month day week wday weight sales_amt price_per_kg sanji_wide2
정가수의 a 20160324 충북원협(충주) 충주도매시장 봉지 107400 당근 1.00 1 서울특별시 송파구 서울특별시 송파구 3 세척당근 kg 2016 3 24 13 목요일 1.00 107400 107400.00 서울특별시
정가수의 a 20161028 익산원협(공) 익산도매시장 상자 945 당근 0.01 5 서울특별시 송파구 서울특별시 송파구 3 기타 kg 2016 10 28 44 금요일 0.05 4725 94500.00 서울특별시
정가수의 a 20160606 전주원협(공) 전주도매시장 상자 22164 당근 0.25 1 서울특별시 송파구 서울특별시 송파구 3 기타 kg 2016 6 6 24 월요일 0.25 22164 88656.00 서울특별시
정가수의 a 20160618 전주원협(공) 전주도매시장 상자 22148 당근 0.25 1 서울특별시 송파구 서울특별시 송파구 3 기타 kg 2016 6 18 25 토요일 0.25 22148 88592.00 서울특별시
정가수의 a 20170801 인터넷청과 구리도매시장 상자 720000 당근 10.00 10 a a NA 3 당근(수입) kg 2017 8 1 32 화요일 100.00 7200000 72000.00 a
정가수의 a 20170803 인터넷청과 구리도매시장 상자 720000 당근 10.00 -10 a a NA 3 당근(수입) kg 2017 8 3 32 목요일 -100.00 -7200000 72000.00 a
정가수의 a 20180315 동부청과 부산반여도매시장 상자 13000 당근 0.20 2 경기도 경기도 NA 3 당근(수입) kg 2018 3 15 12 목요일 0.40 26000 65000.00 경기도
정가수의 a 20160127 원주원협(공) 원주도매시장 상자 15750 당근 0.30 1 서울특별시 송파구 서울특별시 송파구 3 기타 kg 2016 1 27 5 수요일 0.30 15750 52500.00 서울특별시
정가수의 a 20161119 천안농협(공) 천안도매시장 상자 50000 당근 1.00 2 서울특별시 서울특별시 NA 3 흙당근 kg 2016 11 19 47 토요일 2.00 100000 50000.00 서울특별시
경매 a 20170921 무등급 이리청과 익산도매시장 상자 1347368 당근 30.00 1 전라북도 익산시 전라북도 익산시 3 당근(일반) kg 2017 9 21 39 목요일 30.00 1347368 44912.27 전라북도
정가수의 a 20150910 전주원협(공) 전주도매시장 상자 31500 당근 0.75 1 서울특별시 송파구 서울특별시 송파구 3 기타 kg 2015 9 10 37 목요일 0.75 31500 42000.00 서울특별시
경매 a 20170228 무등급 이리청과 익산도매시장 상자 1229166 당근 30.00 1 전라북도 익산시 전라북도 익산시 3 기타 kg 2017 2 28 10 화요일 30.00 1229166 40972.20 전라북도
정가수의 a 20170907 무등급 안양원협(공) 안양도매시장 상자 20000 당근 0.50 1 경기도 안양시 경기도 안양시 3 기타 kg 2017 9 7 37 목요일 0.50 20000 40000.00 경기도
정가수의 a 20170117 무등급 정읍원협(공) 정읍도매시장 78950 당근 2.00 1 광주광역시 광주광역시 NA 3 흙당근 kg 2017 1 17 4 화요일 2.00 78950 39475.00 광주광역시
정가수의 a 20150521 원주원협(공) 원주도매시장 상자 15750 당근 0.40 1 서울특별시 송파구 서울특별시 송파구 3 세척당근 kg 2015 5 21 21 목요일 0.40 15750 39375.00 서울특별시
정가수의 a 20170104 전주원협(공) 전주도매시장 상자 37800 당근 1.00 1 서울특별시 송파구 서울특별시 송파구 3 기타 kg 2017 1 4 2 수요일 1.00 37800 37800.00 서울특별시
정가수의 a 20170201 전주원협(공) 전주도매시장 상자 37800 당근 1.00 1 서울특별시 송파구 서울특별시 송파구 3 기타 kg 2017 2 1 6 수요일 1.00 37800 37800.00 서울특별시
정가수의 a 20170718 무등급 충북원협(청주) 청주도매시장 상자 1793 당근 0.05 10 서울특별시 송파구 서울특별시 송파구 3 세척당근 kg 2017 7 18 30 화요일 0.50 17930 35860.00 서울특별시
자기계산 a 20170125 정일청과 정읍도매시장 상자 69000 당근 2.00 2 광주광역시 북구 광주광역시 북구 9 당근(일반) kg 2017 1 25 5 수요일 4.00 138000 34500.00 광주광역시
정가수의 a 20170826 농협창원(공) 창원팔용도매시장 기타 32000 당근 1.00 1 경상남도 창원시 경상남도 창원시 4 세척당근 kg 2017 8 26 35 토요일 1.00 32000 32000.00 경상남도
정가수의 a 20150718 강릉농산물 강릉도매시장 기타 32000 당근 1.00 10 서울특별시 서울특별시 NA 3 당근(일반) kg 2015 7 18 29 토요일 10.00 320000 32000.00 서울특별시
정가수의 a 20180102 충북원협(충주) 충주도매시장 12780 당근 0.40 1 서울특별시 송파구 서울특별시 송파구 3 기타 kg 2018 1 2 2 화요일 0.40 12780 31950.00 서울특별시
매수도매 2016-03-31 :: 20160331 동화청과 서울가락도매시장 3188 당근 0.10 1 a a NA a 당근(수입) kg 2016 3 31 14 목요일 0.10 3188 31880.00 a
정가수의 a 20170501 6등 충북원협(청주) 청주도매시장 상자 31650 당근 1.00 2 서울특별시 송파구 서울특별시 송파구 3 흙당근 kg 2017 5 1 19 월요일 2.00 63300 31650.00 서울특별시
정가수의 a 20170501 6등 충북원협(청주) 청주도매시장 상자 31650 당근 1.00 20 서울특별시 송파구 서울특별시 송파구 3 흙당근 kg 2017 5 1 19 월요일 20.00 633000 31650.00 서울특별시
정가수의 a 20161128 전주원협(공) 전주도매시장 상자 31649 당근 1.00 1 서울특별시 송파구 서울특별시 송파구 3 기타 kg 2016 11 28 49 월요일 1.00 31649 31649.00 서울특별시
정가수의 a 20150904 전주원협(공) 전주도매시장 상자 31609 당근 1.00 1 서울특별시 송파구 서울특별시 송파구 3 기타 kg 2015 9 4 36 금요일 1.00 31609 31609.00 서울특별시
정가수의 a 20160813 충북원협(청주) 청주도매시장 상자 8440 당근 0.30 1 서울특별시 송파구 서울특별시 송파구 3 세척당근 kg 2016 8 13 33 토요일 0.30 8440 28133.33 서울특별시
정가수의 a 20170301 무등급 정읍원협(공) 정읍도매시장 52640 당근 2.00 1 광주광역시 광주광역시 NA 3 흙당근 kg 2017 3 1 10 수요일 2.00 52640 26320.00 광주광역시
정가수의 a 20161006 전주원협(공) 전주도매시장 상자 25531 당근 1.00 1 서울특별시 송파구 서울특별시 송파구 3 기타 kg 2016 10 6 41 목요일 1.00 25531 25531.00 서울특별시

raw 데이터에서 산지가 송파구인 데이터만 필터링하여 단위가격이 낮은 순에서 높은 순으로 정렬하였다. 약 28,440번째 순위에서 급격하게 증가하는 것을 볼 수 있다. 또한 그 중 1kg 이하의 거래단량을 가진 거래들에서 높은 price_per_kg값들이 많은 것을 확인할 수 있었다.(*raw 데이터는 3개만 g으로 되어있고, 나머지는 모두 kg이었다.) 그래서 다시 1kg 이하의 거래들만 필터링한 결과, 너무 높다 싶은 price_per_kg을 가진 값들은 배제가 되고, 최대 18,900원에서 그치는 것을 볼 수 있었다.

d1 <- dat %>% filter(sanji_city == '송파구')
g1 <- ggplot(d1 %>% arrange(price_per_kg) %>% mutate(SEQ=seq(1,nrow(d1),1))) + geom_line(aes(x=SEQ,y=price_per_kg), linetype='solid', size=0.5, alpha=0.8, color='blue') 
d2 <- d1 %>% filter(prut>1)
g2 <- ggplot(d2 %>% arrange(price_per_kg) %>% mutate(SEQ=seq(1,nrow(d2),1))) + geom_line(aes(x=SEQ,y=price_per_kg), linetype='solid', size=0.5, alpha=0.8, color='blue') 
subplot(ggplotly(g1),ggplotly(g2), margin = 0.05, nrows=2)

산지가 송파구인 것들 중 1kg 이하의 거래는 제거한 후 dat2 데이터를 만들었다.

dat2 <- dat %>% filter(!(sanji_city == '송파구' & prut<=1))

다시 kg당 5,000원 이상의 거래를 확인해보자(좌편-상단). 개수는 약 350개로 적지만, 여전히 이상치가 존재하는 것을 알 수 있다. 우편-상단 -> 좌편-하단 -> 우편-하단 그래프 순으로 살펴보면 배추처럼 price_per_kg이 높을수록 거래량이 적어지는 현상같은 건 나타나지 않고, 중간중간 물량이 있는 가격대가 있어 계단 모양을 보이고 있다.

d3 <- dat2 %>% arrange(price_per_kg) %>% mutate(SEQ=seq(1,nrow(dat2),1)) %>% filter(price_per_kg >= 5000)
g3 <- ggplot(d3) + geom_line(aes(x=SEQ,y=price_per_kg), linetype='solid', size=0.5, alpha=0.8, color='red') 
d3a <- dat2 %>% arrange(price_per_kg) %>% mutate(SEQ=seq(1,nrow(dat2),1)) %>% filter(SEQ > 552800, SEQ < 552900) 
d3b <- dat2 %>% arrange(price_per_kg) %>% mutate(SEQ=seq(1,nrow(dat2),1)) %>% filter(SEQ > 552900, SEQ < 553000)  
d3c <- dat2 %>% arrange(price_per_kg) %>% mutate(SEQ=seq(1,nrow(dat2),1)) %>% filter(SEQ > 553000, SEQ < 553100) 
g3a <- ggplot(d3a) + geom_line(aes(x=SEQ,y=price_per_kg), linetype='solid', size=0.5, alpha=0.8, color='red1')
g3b <- ggplot(d3b) + geom_line(aes(x=SEQ,y=price_per_kg), linetype='solid', size=0.5, alpha=0.8, color='red2') 
g3c <- ggplot(d3c) + geom_line(aes(x=SEQ,y=price_per_kg), linetype='solid', size=0.5, alpha=0.8, color='red3') 
subplot(ggplotly(g3),ggplotly(g3a), ggplotly(g3b), ggplotly(g3c), margin = 0.05, nrows=2) 

분석에서는 당근의 일반적인 도매가격을 고려하여, 앞선 dat2 데이터에 100원 이상 5,000원 이하의 조건을 추가시킨 dat3 데이터(551,685개)를 활용하였다.

dat3 <- dat %>% filter(!(sanji_city == '송파구' & prut<=1) & (price_per_kg <= 5000 & price_per_kg >= 100))
연도-월 반입량

먼저 연도-월 반입량을 보자. 뚜렷하게 나타나는 계절적 특징같은 것은 없지만, 17년 4월에 반입량이 급증하여, 18년 2월까지 비교적 높은 추세를 유지하는 것을 볼 수 있다.

input_year_month <- dat3 %>% group_by(year,month) %>% summarise(input=sum(weight,na.rm=T)) %>% spread(month,input,fill=0) %>% ungroup()
d5 <- as.matrix(input_year_month[,-1])/1000
hist3D(z = d5, x = as.numeric(t(input_year_month[,1])), y = 1:12, scale = F, expand = 0.00005, bty = "g", phi = 30, theta = 20, col = jet.col(100), alpha = 0.5, border = "black", shade = 0.2, ltheta = 90, space = 0.4, ticktype = "detailed", d = 2, xlab='year',ylab='month',zlab='ton')

연도-월 가격

다음은 연도-월 가격을 살펴보자. 16년 말에서 17년으로 넘어가는 시기에 가격이 급증했었다가 안정세로 돌아온다. 당시의 뉴스를 살펴보면, 출하량이 작년 같은 기간에 비해 50% 감소할 전망으로 도매가격의 급상승이 예상된다는 내용들이 있다. 전체적으로는 15년초와 비교했을 때 꾸준히 가격이 오르는 편이다. 또한, 6~9월에 가격이 높은 편이라고 할 수 있는데, 이 때가 당근의 최대출하지인 제주의 주출하시기가 아니어서 출하량이 적기 때문에 이러한 현상이 나타나는 것으로 추정된다.

price_year_month <- dat3 %>% group_by(year,month) %>% summarise(price=mean(price_per_kg,na.rm=T)) %>% spread(month,price,fill=0) %>% ungroup()
d6 <- as.matrix(price_year_month[,-1])
hist3D(z = d6,  x = as.numeric(t(price_year_month[,1])), y = 1:12, scale = FALSE, expand = 0.002, bty = "g", phi = 30, theta = 20, col = jet.col(100), alpha = 0.5, border = "black", shade = 0.2, ltheta = 90, space = 0.4, ticktype = "detailed", d = 2, xlab='year',ylab='month',zlab='W/kg')

산지-월 출하량

산지-월 출하량이다. 일단 산지가 들어가 있지 않은 결측데이터가 많고, 그것을 제외하면 제주와 경남의 출하량이 가장 많다. 제주의 경우는 12~4월, 경남의 경우는 그 다음부터인 5~9월이 가장 많다. 부산의 경우엔 경남과 마찬가지로 5~9월이 주출하시기라고 할 수 있다. 강원의 경우, 제주와 경남 모두 주출하시기가 아닌 9~11월 틈새에 주로 출하되는 것을 알 수 있다.

input_sanji_month <- dat3 %>% group_by(sanji_wide2,month) %>% summarise(input=sum(weight,na.rm=T)) %>% spread(month,input,fill=0) %>% ungroup()
input_sanji_month <- input_sanji_month %>% mutate(total=apply(input_sanji_month[,-1],1,sum)) %>% arrange(desc(total))
d8 <- as.matrix(input_sanji_month[1:9,2:13])/1000
hist3D(z = d8, x=1:9, y=1:12, scale = FALSE, expand = 0.0001, bty = "g", phi = 40, theta = 20, col = jet.col(100), alpha = 0.5, border = "black", shade = 0.2, ltheta = 90, space = 0.4, ticktype = "detailed", d = 2, xlab="결측 제주 경남 부산 강원 중국 서울 경기 경북", ylab="month", zlab='ton', cex.lab=1.1)

품종-월 반입량

이번엔 품종-월 반입량을 보자. 당근(일반), 당근(수입), 기타, 이 세 품종이 가장 많은 반입량을 차지하고 흙당근이 그 다음이다. 셋 모두 1~6,7월까지는 반입량이 많고 하반기에는 낮아지는 추세이다. 기타가 전체에서 세번째로 높은 반입량을 차지하는데, 이것만으로는 기타가 어떤 당근을 의미하는지 알기 힘들다.

input_spec_month <- dat3 %>% group_by(spename,month) %>% summarise(input=sum(weight,na.rm=T)) %>% spread(month,input,fill=0) %>% ungroup()
input_spec_month <- input_spec_month %>% mutate(total=apply(input_spec_month[,-1],1,sum)) %>% arrange(desc(total))
d9 <- as.matrix(input_spec_month[1:7,2:13])/1000
hist3D(z = d9, x=1:7, y=1:12, scale = FALSE, expand = 0.0001, bty = "g", phi = 40, theta = 20,  col = jet.col(100), alpha = 0.5, border = "black", shade = 0.2, ltheta = 90, space = 0.4, ticktype = "detailed", d = 2, xlab="일반 수입 기타 흙 세척 꼬마 세척수입", ylab="month", zlab='ton', cex.lab=1.1)

품종-산지 출하량

수입당근의 산지가 압도적으로 결측지역인 것으로 보아, 외국은 산지를 입력하지 않은 것이 대다수인 것으로 추정된다. 하지만 중국의 경우도 있으므로, ‘외국은 산지를 입력하지 않는다’라고 단정짓진 못할 것 같다. 기타의 경우에도 결측지역이 가장 많고, 일반은 최대출하지인 제주와 경남에서 가장 많은 것으로 나타난다. 부산의 경우엔 일반보다 기타의 비중이 큰 것을 알 수 있다.

input_spec_sanji_wide2 <- total_sort_2d(dat3,spename,sanji_wide2,weight)
d10 <- as.matrix(input_spec_sanji_wide2[1:9,2:8])/1000
hist3D(z = d10, x=1:9, y=1:7, scale = FALSE, expand = 0.0001, bty = "g", phi = 50, theta = 120, col = jet.col(100), alpha = 0.5, border = "black", shade = 0.2, ltheta = 90, space = 0.4, ticktype = "detailed", d = 2, xlab="경북 경기 서울 중국 강원 부산 경남 제주 결측", cex.lab=1.0, ylab="일반 수입 기타 흙 세척 꼬마 세척수입", zlab='ton')

위와 같은 과정을 통해, 분석 대상 품종을 당근(일반), 당근(수입), 기타로 좁히고 데이터 가공을 시작했다.

거래단위별 가격이다. 가장 거래량이 많은 6개의 거래단위를 대상으로 했는데, 10kg와 20kg의 상자, 파렛트, 기타가 선정되었다. 막대그래프를 보면 20kg단위의 가격대가 10kg단위보다 높은 편인 것을 알 수 있다.

subplot(ggplotly(gg1.4a,tooltip = c("x", "y")),ggplotly(gg1.4b,tooltip = c("x", "y")),ggplotly(gg1.4c,tooltip = c("x", "y")),ggplotly(gg1.4d,tooltip = c("x", "y")),ggplotly(gg1.4e,tooltip = c("x", "y")), margin = 0.05, nrows=5)

마지막으로 법인별/거래방법별 반입량과 가격대이다. 반입량은 서울이 압도적으로 많은 것을 알 수 있고, 그 다음으로 부산, 광주, 대구 순이다. 가격대는 주로 1,000원 이하의 가격대를 보여주고 있고, 광주각화도매시장의 경우 현저히 낮은 것으로 나온다.

formattable(tab_2_1, list(
  mkt_short=formatter(
    "span",
    style = x ~ ifelse(x == substr(mkt_sel,1,4), style(font.weight = "bold", color = 'blue'), NA)),
  amt_ton = color_tile("white", "orange"),
  area(col = c(price_l1w, price_l2w, price_l3w)) ~ normalize_bar("pink", 0.2, na.rm=T)
))
mkt_short insname amt_ton price_l1w price_l2w price_l3w
서울가락 한국청과 104340 847 839 863
서울가락 동화청과 49477 832 798 840
서울가락 서울청과 47566 836 818 829
서울가락 중앙청과 43857 850 787 835
부산엄궁 부산청과 22164 880 900 900
광주각화 광주원협(공) 18000 460 NA 300
대구북부 효성청과 14880 920 950 890
대전오정 농협대전(공) 13217 878 842 882
구리도매 인터넷청과 13029 891 894 884
구리도매 구리청과 10626 940 937 925
인천삼산 경인농산 9963 900 900 900
대전노은 대전중앙청과 9525 826 795 841
구리도매 농협구리(공) 9521 895 839 869
인천삼산 삼산원협(공) 9045 900 900 900
인천구월 인천농산물 8635 884 883 864
대전오정 대전청과(주) 8536 880 850 880
광주서부 농협광주(공) 8450 1000 NA 997
순천도매 순천원협(공) 8190 900 950 900
서울강서 서부청과 7650 842 861 NA
부산반여 농협반여(공) 7485 904 927 1027
ggplotly(g, tooltip = c('x',"y"), height = 600)
서승현 avatar
About 서승현
서승현
comments powered by Disqus