KKTV Data Game practice
這是第二次參加KKTV舉辦的比賽,這次比賽主要是透過用戶觀測資料去預測用戶在未來的一週各個時段是否會觀劇?
主辦單位也很用心的提供了幾個benchmark,以下就帶大家來一一實作,首先先介紹資料前處理方法,接下來介紹各模型。
- Data preprocessing
2. Modeling
3. Ensemble learning
1.1 data preprocessing
training data 分散在45個csv中,我們篩選近三個月的資料並且觀看時間大於5分鐘的行為當作有效的行為,並合成一個大的dataframe。
files <- list.files("Downloads/")
for(file in files) {
data <- fread(file)
final_data <- data_frame()
data %<>%
filter(played_duration > 300 %>%
mutate(event_time=as.POSIXct(event_time)) %>%
filter(event_time > '2017-05-01 00:00:00' )
final_data <- rbind(final_data,data)
}
time_slot的切法,就照著資料描述裡面的定義
timeslot0 : 01:00:00 ~ 09:00:00
timeslot1 : 09:00:00 ~ 17:00:00
timeslot2 : 17:00:00 ~ 21:00:00
timeslot3 : 21:00:00 ~ 01:00:00
user_matrix <- final_data %>%
select(user_id,event_time,played_duration) %>%
mutate(event_start_time=event_time-played_duration) %>%
mutate(time_slot_end=ifelse(strftime(event_time,"%H:%M:%S") >= '01:00:00' & strftime(event_time,"%H:%M:%S") < '09:00:00',0,
ifelse(strftime(event_time,"%H:%M:%S") >= '09:00:00' & strftime(event_time,"%H:%M:%S") < '17:00:00',1,
ifelse(strftime(event_time,"%H:%M:%S") >= '17:00:00' & strftime(event_time,"%H:%M:%S") < '21:00:00',2,
ifelse(strftime(event_time,"%H:%M:%S") >= '21:00:00' | strftime(event_time,"%H:%M:%S") < '01:00:00',3,NA))))) %>%
mutate(time_slot_start=ifelse(strftime(event_start_time,"%H:%M:%S") >= '01:00:00' & strftime(event_start_time,"%H:%M:%S") < '09:00:00',0,
ifelse(strftime(event_start_time,"%H:%M:%S") >= '09:00:00' & strftime(event_start_time,"%H:%M:%S") < '17:00:00',1,
ifelse(strftime(event_start_time,"%H:%M:%S") >= '17:00:00' & strftime(event_start_time,"%H:%M:%S") < '21:00:00',2,
ifelse(strftime(event_start_time,"%H:%M:%S") >= '21:00:00' | strftime(event_start_time,"%H:%M:%S") < '01:00:00',3,NA)))))
這邊跨time_slot的處理比較偷懶,假如從八點看到十點,會在slot0和slot1都各記上二小(以後有機會在改掉)。
2–1. regression
一開始看到迴歸可以得到這麼好的結果有點嚇到,因為當我們一開始看到這個問題時,就覺得每個User的觀劇行為應該是很不一樣的,所以應該很難用同一個model去描述所有人的行為,我們一開始使用facebook release的時間序列資料預測方法-Prophet,根據每個User前32週的資料去預測,準確率最高大概80.3%,後來看到迴歸準確率可以到那麼高真的有點錯愕。
丟進迴歸資料就像官方公布的圖一樣,用前32周的資料與timeslot去建立迴歸,預測第33周,然後每個User應該會有28筆資料分別是28個timeslot。
原本整理的時間格式 2017–08–21–0 (日期後面加上屬於哪個timeslot) 拆成日期與timeslot,將日期轉成屬於第幾週
format(as.Date(date), “%W”)
利用weekdays
function 得到該日期是星期幾,整理好資料後,就可以利用lm
開始建立迴歸模型拉。
2–2. convolutional neural network
因為這次的比賽才有機會接觸CNN,透過tensorflow實作了簡單的CNN,根據第二名的大大分享用前六週的資料去訓練是最佳的,所以input放入
- 六週 28個timeslot 每個timeslot的觀看時間
dataset = np.loadtxt("/Users/ricky/Desktop/train.csv", delimiter=",")
X = dataset[:,0:168] # 前六週
Y = dataset[:,168:196]
X = X.reshape(51807,6,28,1)sequence_input = Input(shape=(6, 28, 1))
x = sequence_input
x = Conv2D(32, (1, 3), activation='relu')(x)
x = Dropout(0.75)(x)x = Dense(64, activation='relu')(x)
x = Dropout(0.75)(x)x = Flatten()(x)
x = Dense(64, activation='relu')(x)
preds = Dense(28, activation='sigmoid')(x)model = Model(sequence_input, preds)model.compile(loss='binary_crossentropy',
optimizer='adam',
metrics=['acc'])
2–3. xgboost
之前有稍微摸一下xgboost這個套件,但一直沒在比賽中實作,這次剛好有機會可以來實際運用看看,input跟迴歸一樣是32週的資料加上time_slot
一開始要將data轉成sparse matrix,在使用sparse.model.matrix時,第一行會產生1這個intercept,一般在用xgboost,都會寫成~.-1,把intercept移除
sparse_matrix <- Matrix::sparse.model.matrix(week33 ~ .-1, data = xgb_train[,-1])
接著就可以開始建立model
output_vector = xgb_train[,"week33"]
bstSparse <- xgboost(data = sparse_matrix, label = output_vector, eta = 0.1, nthread = 2, nrounds = 200, objective = "binary:logistic")
3–1. bagging
很多kaggle的比賽前面的名次,最後都是以ensemble learning再去優化模型,整體學習的概念其實就是將數個分類器的預測結果綜合考慮,藉此達到顯著提升分類效果。而bagging是通過組合隨機生成的訓練集而改進分類的集成算法。
train_ensemble$true <- as.factor(train_ensemble$true)
bag_fit <- bagging(true ~ xgboost + lm, data = train_ensemble, mfinal = 30)
test_pred <- predict(bag_fit, test_ensemble)
這邊ensemble learning的方法好像還需要在試看看,不知道為啥bagging的結果居然是最爛的。
Reference
[1] 第二名分享
[2] 官方benchmark公開
[3]集成學習說明