데이터분석2016. 5. 31. 17:23

Google Calendar에 추가한 Goal Alarm이 오질 않네요 여튼 그래서 수동으로 다시 시작합니다. 5일차때 다룬 Rossmann Store Sales 풀이 이어서 나가도록 하겠습니다.  저번에 제공 데이터를 str. summary 등의 함수를 가지고 한번 훑어보았데 train데이터만 보여줬는데 마저 test 데이터도 조회해보죠

summary(test)
##        Id            Store          DayOfWeek          Date           
##  Min.   :    1   Min.   :   1.0   Min.   :1.000   Min.   :2015-08-01  
##  1st Qu.:10273   1st Qu.: 279.8   1st Qu.:2.000   1st Qu.:2015-08-12  
##  Median :20544   Median : 553.5   Median :4.000   Median :2015-08-24  
##  Mean   :20544   Mean   : 555.9   Mean   :3.979   Mean   :2015-08-24  
##  3rd Qu.:30816   3rd Qu.: 832.2   3rd Qu.:6.000   3rd Qu.:2015-09-05  
##  Max.   :41088   Max.   :1115.0   Max.   :7.000   Max.   :2015-09-17  
##                                                                       
##       Open            Promo        StateHoliday       SchoolHoliday     
##  Min.   :0.0000   Min.   :0.0000   Length:41088       Length:41088      
##  1st Qu.:1.0000   1st Qu.:0.0000   Class :character   Class :character  
##  Median :1.0000   Median :0.0000   Mode  :character   Mode  :character  
##  Mean   :0.8543   Mean   :0.3958                                        
##  3rd Qu.:1.0000   3rd Qu.:1.0000                                        
##  Max.   :1.0000   Max.   :1.0000                                        
##  NA's   :11
test[is.na(test$Open), ] # Only store 622
##        Id Store DayOfWeek       Date Open Promo StateHoliday SchoolHoliday
##  1: 10752   622         6 2015-09-05   NA     0            0             0
##  2:  9040   622         1 2015-09-07   NA     0            0             0
##  3:  8184   622         2 2015-09-08   NA     0            0             0
##  4:  7328   622         3 2015-09-09   NA     0            0             0
##  5:  6472   622         4 2015-09-10   NA     0            0             0
##  6:  5616   622         5 2015-09-11   NA     0            0             0
##  7:  4760   622         6 2015-09-12   NA     0            0             0
##  8:  3048   622         1 2015-09-14   NA     1            0             0
##  9:  2192   622         2 2015-09-15   NA     1            0             0
## 10:  1336   622         3 2015-09-16   NA     1            0             0
## 11:   480   622         4 2015-09-17   NA     1            0             0
test$Open[test$Store == 622]
##  [1]  1  0  1  1  1  1  1  1  0  1  1  1  1  1  1  0  1  1  1  1  1  1  0
## [24]  1  1  1  1  1  1  0  1  1  1  1  1 NA  0 NA NA NA NA NA NA  0 NA NA
## [47] NA NA


여기에서 보면 위에 제가 볼드체로 표시한 부분 즉 실제 rows수를 보면 train데이터가 월등히 많네요. 1017209rows에 비해 test데이터는 턱없이 부족하고 그리고 dashboard에 issue로 올라온 것보면 622개의 데이터가 Open 컬럼이 NA로 되어있어 못쓴다라고 올라와있는데요. 하지만 이 row를 못쓰는건 아닙니다.  여기를 보면 아시다시피 Sale라는 컬럼이 닫혀있다면 0일수가 없으니 1로 간주하면 될거 같습니다. 이런걸 data munging이라고도 하는데 저희가 도메인을 파악하고 어떤 이유에서인지 알수 없거나 정리가 안된걸 직접 수정하여 trim처리를 하는 센스는 있어야 합니다.  게다가 테스트 데이터에는 Customers컬럼이 아예 빠져있는걸 알수 있습니다. 사후 데이터이기 때문이라네요 ?


여튼  그래서 아래와 같은 처리 합니다. NA인 녀석들을 싹다!!!!  1로 만들어버립시다


test[is.na(test)] <- 1

위의 문법은 test의 컬럼중 NA를 다 1로 채우는걸로 이해하면 됩니다


그다음에 다시

test[is.na(test$Open), ]
하면 결과가 0이 나올겁니다 테스트 데이터에는 Easter Day나 크리스마스 휴일가 없지만 방학은 44프로나 있네요. 하지만 그에 비해 train data의 18프로만의 방학이 있다는거 뭔가 데이터가 참 bias된것 같습니다. 이 점을 참고해야겠죠??

# Unique values per column
train[, lapply(.SD, function(x) length(unique(x)))]
##    Store DayOfWeek Date Sales Customers Open Promo StateHoliday
## 1:  1115         7  942 21734      4086    2     2            4
##    SchoolHoliday
## 1:             2
test[, lapply(.SD, function(x) length(unique(x)))]
##       Id Store DayOfWeek Date Open Promo StateHoliday SchoolHoliday
## 1: 41088   856         7   48    2     2            2             2
.SD가 여기서 궁금한 분은 이 링크를 보세요. 보면 SchoolHoliday가 test에는 2 train에는 4(부활절, 크리스마스 포함)인 걸 알수가 있네요. 그리고 Store의 각 개수가 1115, 856개 각각 인거도 보시구요~

그리고 아래는 train의 데이터들에 있는 상점들이 test의 상점들을 다 포함하는걸로 볼수 있죠 

# All test stores are also in the train data
sum(unique(test$Store) %in% unique(train$Store)) 
## [1] 856

하지만 반대의 경우는 성립하지가 않네요. 고작 259개만 커버를 하네요 나머지 1115에서 259개를 뺀건 포함을 못한다는 얘기죠?!
# 259 train stores are not in the test data
sum(!(unique(train$Store) %in% unique(test$Store))) 
## [1] 259
그리고 아래는 참 유용한 표현식입니다. factor형일 경우 전체 row에서 %를 알고 싶을때 자주 쓰죠
table(train$Open) / nrow(train) # Percent Open Train
## 
##         0         1 
## 0.1698933 0.8301067
train 데이터의 경우 열려있는경우가 83%나 되는걸 볼수가 있습니다..

table(test$Open) / nrow(test) # Percent Open Test 
## 
##         0         1 
## 0.1456386 0.8543614
테스트 데이터에서도 비슷하게 85%네요

table(train$Promo) / nrow(train) # Percent of the time promo in train
## 
##         0         1 
## 0.6184855 0.3815145
흠 train데이터에서는 프로모션을 38%나 하네요

table(test$Promo) / nrow(test) # Percent of the time promo in test
## 
##         0         1 
## 0.6041667 0.3958333
39프로 역시나 test데이터에서도 유사합니다

table(train$StateHoliday) / nrow(train) # Percent of the time holiday in train
## 
##           0           a           b           c 
## 0.969475300 0.019917244 0.006576820 0.004030637
흠 그리고 State 휴일이 아닌게 97%  당연하죠.. a,b,c는 데이터셋 설명 다시 보시길 ㅋ

table(test$StateHoliday) / nrow(test) # no b and c = no easter holiday and no christmas
## 
##           0           a 
## 0.995619159 0.004380841
핫 여기 보면 test데이터는 뭔가 bias되었네요 확실히.. bc 데이터가 없네요... 아 이게 부활절하고 크리스마스를 bc라고 지칭한건가 싶네요..

table(train$SchoolHoliday) / nrow(train) # Percent of the time school holiday in train
## 
##         0         1 
## 0.8213533 0.1786467
table(test$SchoolHoliday) / nrow(test) # Percent of the time school holiday in test
## 
##         0         1 
## 0.5565129 0.4434871
여기서도 차이가 아까 말한것처럼 발견되죠..... 이건 위에 언급했으니 넘어가겠습니다..ㅎㅎ 
데이터가 뭔가 구린건 없네요. test 데이터의 기간은 2015년 8월 1일부터 2015년 9월 17일 즉 우리 이 과제의 목표는 48일간을 예측해야하는거네요. train데이터의 기간은 2013/1/1~ 2015/7/31 한... 2.5년치의 데이터를 가지고 있다고 보면 되겠네요... 뭔가 흥미진진하죠? 그런데 테스트데이터가 적어서 좀 그렇네요?? 자 봅시다..

plot(train$Date, type = "l")

plot(test$Date, type = "l")
이런거를 plot으로 찍어서 기간을 산정해보기도하는군요 -ㅅ- min max를 plot으로 쉽게 알수 있으니 걍 쓰는가봅니다 --a

아래는 테스트의 unique  store개수가 856 였던거 기억하죠? 그 spread기간동안 데이터가 온전히 다 있나 체크하는고

# As expected all 856 stores to be predicted daily
all(table(test$Date) == 856) 
## [1] TRUE

흠 그다음은 train 데이터에서 특정 컬럼 값 분포를 봅시다. 
Sales라는 컬럼보면 대충 값들이 5000정도에서 맥스 찍고 20000이 되면서 줄어드는게 좌편향 정규분포 비슷하게 그리네요 

hist(train$Sales, 100)

다음은 historgram을 또 그리는데 "가게 문을 안닫았을때의 가게별 평균 sales"를 봅시다.  즉 Store별로  Sales를 평균 낸 데이터를 가지고 다시 히스토그램을 100분위로 나타낸것이다.
아래는 hist와 aggregate를 두개로 split해서 보시면 될듯합니다. 자세한 건 documentation 보면서 이해하는수밖에 없습니다 ^^

hist(aggregate(train[Sales != 0]$Sales, 
               by = list(train[Sales != 0]$Store), mean)$x, 100, 
     main = "Mean sales per store when store was not closed")

그다음은 custormers수의 분포를 봅시다.
hist(train$Customers, 100)



그리고 그다음은 아까 sales를 100분위로 histogram으로 나타낸것과 똑같이 고객수를 나타내보겠습니다.
hist(aggregate(train[Sales != 0]$Customers, 
               by = list(train[Sales != 0]$Store), mean)$x, 100,
     main = "Mean customers per store when store was not closed")

가게 넘버가 500~1000으로 부여된것이 실적이 좋네요 ㅎㅎ

그리고 ggplot으로 이제 뿌릴건데요  boxplot도 안에 껴서 그릴수가있습니다.

학교 휴일이냐 아니냐에 따라서 판매량을 한번 볼게요 

ggplot(train[Sales != 0], aes(x = factor(SchoolHoliday), y = Sales)) +
    geom_jitter(alpha = 0.1) +
    geom_boxplot(color = "yellow", outlier.colour = NA, fill = NA)

box plot으로는 차이가 별로 없고 판매량은 휴일이 아닌경우 가 확실히 더 많네요. 까만영역이 더 높죠?!


후배님께서 술먹자고 가자고 하네요. 후아. 오늘도 여기까지. 아직 반도 안왔네요. 이거 !!  그래도 다음 차에는 확 끝내겠습니다!


































'데이터분석' 카테고리의 다른 글

Kaggler's Day #8  (0) 2016.06.10
Kaggler's Day #7  (0) 2016.06.08
Kaggler's Day #5  (0) 2016.05.27
Kaggler's Day #3  (0) 2016.05.16
Kaggler's Day #1  (0) 2016.05.12
Posted by 억사마