# This R environment comes with all of CRAN preinstalled, as well as many other helpful packages
# The environment is defined by the kaggle/rstats docker image: https://github.com/kaggle/docker-rstats
# For example, here's several helpful packages to load in 

library(ggplot2) # Data visualization
library(readr) # CSV file I/O, e.g. the read_csv function
suppressPackageStartupMessages(library(dplyr, quietly=TRUE))
suppressPackageStartupMessages(library(data.table, quietly=TRUE))
suppressPackageStartupMessages(library(bit64, quietly=TRUE))
suppressPackageStartupMessages(library(stats, quietly=TRUE))
suppressPackageStartupMessages(library(lubridate, quietly=TRUE))
suppressPackageStartupMessages(library(xgboost, quietly=TRUE))
suppressPackageStartupMessages(library(Matrix, quietly=TRUE))
# Input data files are available in the "../input/" directory.
# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory

system("ls ../input")

# Any results you write to the current directory are saved as output.

train <- fread("../input/train.csv", header = T, stringsAsFactors = F)
#test <- fread("../input/test.csv", header = T, stringsAsFactors = F)

head(train)

dim(train)


#test$place_id <- as.integer64(-1)

train$MYTYPE <- 1
#test$MYTYPE <- 2

#df_all <- rbind(train, test)
df_all <- train

# below is R version of a function in the followinf python script
# https://www.kaggle.com/rshekhar2/facebook-v-predicting-check-ins/xgboost-cv-example-with-small-bug

assign_cell <- function(data, X, Y) {

  X = as.integer(X)
  Y = as.integer(Y)

  x_bounds = c(0., 10.)
  y_bounds = c(0., 10.)

  dX <- (as.double(x_bounds[2]) - as.double(x_bounds[1])) / as.double(X)
  dY <- (as.double(y_bounds[2]) - as.double(y_bounds[1])) / as.double(Y)

  print(dX)
  print(dY)
  
  print(x_bounds[1])
  print(y_bounds[1])
  xcells <- floor(as.double(data$x) - as.double(x_bounds[1]))/dX
  ycells <- floor(as.double(data$y) - as.double(y_bounds[1]))/dY
  
  xcells[xcells == X] = X-1
  ycells[ycells == Y] = Y-1

  print(xcells[1])
  print(xcells[2])
  print(ycells[1])
  print(ycells[2])
  
  xl = sprintf("x_cell_%03d", X)
  yl = sprintf("y_cell_%03d", Y)
  
  data[, paste(xl)] <- -1
  data[, paste(yl)] <- -1
  
  head(data)
  data[, paste(xl)] <- xcells
  data[, paste(yl)] <- ycells
  
  return(data)
}

df_all <- assign_cell(df_all, 100, 100)

dim(df_all)
print("Assigned cells")

df_all <- df_all[df_all$x_cell_100==10, ]
df_all <- df_all[df_all$y_cell_100==10,]

df_all <- df_all %>% group_by(place_id) %>% summarise(MYTYPE, x_m = 1000*x, y_m = 1000*y, la = log(accuracy,10), hour = round(time/60)%%24, dow = ceiling(((time/60)/24) %% 7), q = floor(((time) / (6*60)) %% 4))

print("Reducing to usable columns")
dim(df_all)

#df <- assign_cell(df, 100, 100)

#head(df)

df_train <- df_all[df_all$MYTYPE == 1,]
head(df_train)
dim(df_train)
#df_test <- df_all[df_all$MYTYPE == 2,]
df_train$MYTYPE <- NULL
#df_test$MYTYPE <- NULL

# select cell (10,10)
#sample 2000 rows
df_t <- df_train[sample(nrow(df_train), 2000),]

dim(df_t)

df_t$place_id_1 <- df_t$place_id
df_t$place_id_1 <- as.factor(df_t$place_id_1)
levels(df_t$place_id_1) <- 1:length(levels(df_t$place_id_1))
df_t$place_id_1 <- as.numeric(df_t$place_id_1)-1


train.y.1 <- df_t$place_id_1
train.y.2 <- df_t$place_id


df_t$place_id = NULL

df_t$place_id_1 = NULL
head(df_t)
dim(df_t)
#train1 <- sparse.model.matrix(place_id_1 ~ ., data = df_t)
train1 <- data.matrix(df_t)
dtrain <- xgb.DMatrix(data=train1, label=train.y.1)


watchlist <- list(train=dtrain)

num.class = length(unique(train.y.1))
map3 <- function(preds, dtrain) {
  labels <- as.list(getinfo(dtrain,"label"))
  num.class = length(unique(train.y.1))
  pred <- matrix(preds, nrow = num.class)
  top <- t(apply(pred, 2, function(y) order(y)[num.class:(num.class-4)]-1))
  top <- split(top, 1:NROW(top))
  map <- mapk(3, labels, top)
  return(list(metric = "map3", value = map))
}


param <- list(  objective           = "multi:softprob",
                booster             = "gbtree",
                feval               = "map3",
                num_class           = length(unique(train.y.1)),
                eta                 = 0.02,
                alpha               = 0.1,
                lambda              = 0.1,
                max_depth           = 5,
                subsample           = 0.9,
                colsample_bytree    = 0.7
)
# 

bst.cv = xgb.cv(param = param
             , data = dtrain
             , nrounds  = 500
             , nfold = 5
             , stratified = T
             , print.every.n = 1
             , watchlist = watchlist
             , early.stop.round = 10
             , maximize            = FALSE
             , verbose = TRUE
)


# The script runs for longer than 1200 seconds allowed by Kaggle user

# Running the script with test data is left as an exercise to the user.

# Basically uncomment some lines above involving test data set

# Then use the code below

clf <- xgb.train(param,
                 data=dtrain,
                 nrounds             = XXXXX, /* fill this from CV run */
                 verbose             = 0,
                 #watchlist           = watchlist,
                 maximize            = FALSE
)

df_t1 <- df_test[df_test$x_cell_100==10, ]
df_t1 <- df_t1[df_t1$y_cell_100==10,]

dim(df_t1)
#sample 5000 rows
df_t1 <- df_t1[sample(nrow(df_t), 5000),]

dim(df_t1)

df_t1$place_id_1 <- -1
dtest <- xgb.DMatrix(data=test1)

preds <- predict(clf, dtest)

# Now convert preds to place_ids. For doing this sort the proabilities and take their indices. Then map the indices to place_1,
# then to place_id
# This left as an exercise to user