Creating Engagement Milestone Detection Ensemble Model
High-Level Explanation
First Layer | Final Layer |
---|---|
Probability-To-Leave Prediction Model | Left-Too-Early Detection Model |
Time-To-Leave Prediction Model |
-
Should the probability-to-leave be greater than 50% or “time-to-leave” is less than 5 seconds, it activates the “Left-Too-Early Detection Model”. For the latter metric, even if the “Probability-To-Leave Prediction Model” says the player is unlikely to leave, we still have a chance that the player will leave in near term within a short period of time and the effects of player leaving is generally permanent.
-
The “Time-To-Leave Prediction Model” is in the same layer as “Probability-To-Leave Prediction Model” because we want it to constantly produce update on how long the player will stay. If we were to put it between the first and final layer, the updates will be too sparse to predict accurate wait times for “Play Time Maximization Model”.
Code
Feature Vector
local function getPlayerDataVectors(Player)
local playerDataVectorWithBias = {
{
1,
numberOfCurrencyAmount,
numberOfItemsAmount,
timePlayedInCurrentSession,
timePlayedInAllSessions,
healthAmount
}
}
local playerDataVectorWithoutBias = {
{
numberOfCurrencyAmount,
numberOfItemsAmount,
timePlayedInCurrentSession,
timePlayedInAllSessions,
healthAmount
}
}
return playerDataVectorWithBias, playerDataVectorWithoutBias
end
Creating Time-To-Leave And Probability-To-Leave Prediction Models
local TimeToLeavePredictionModel = DataPredict.Models.LinearRegression.new({maximumNumberOfIterations = 100, learningRate = 0.01})
local ProbabilityToLeavePredictionModel = DataPredict.Models.LogisticRegression.new({maximumNumberOfIterations = 100, learningRate = 0.01})
local LeftToEarlyPredictionModel = DataPredict.Models.SupportVectorMachine.new({maximumNumberOfIterations = 100, beta = 1, kernelFunction = "RadialBasisFunction"})
-- The code shown below checks if we already have trained the models previously.
if (TimeToLeavePredictionModelParameters) then TimeToLeavePredictionModel:setModelParameters(TimeToLeavePredictionModelParameters) end
if (ProbabilityToLeavePredictionModelParameters) then ProbabilityToLeavePredictionModel:setModelParameters(ProbabilityToLeavePredictionModelParameters) end
if (LeftToEarlyPredictionModelParameters) then LeftToEarlyPredictionModel:setModelParameters(LeftToEarlyPredictionModelParameters) end
Constructing Play Time Maximization Model
Player Data Collection
local playerDataMatrixWithBias = {}
local playerDataMatrixWithoutBias = {}
local recordedTimeArray = {}
local snapshotIndex = 1
local function getPlayerDataArrays()
local playerDataArrayWithBias = {
1,
numberOfCurrencyAmount,
numberOfItemsAmount,
timePlayedInCurrentSession,
timePlayedInAllSessions,
healthAmount
}
local playerDataArrayWithoutBias = {
numberOfCurrencyAmount,
numberOfItemsAmount,
timePlayedInCurrentSession,
timePlayedInAllSessions,
healthAmount
}
return playerDataVectorWithBias, playerDataVectorWithoutBias
end
local function snapshotData(playerDataArray)
playerDataMatrixWithBias[snapshotIndex], playerDataMatrixWithoutBias[snapshotIndex] = getPlayerDataArrays()
recordedTimeArray[snapshotIndex] = os.time()
snapshotIndex = snapshotIndex + 1
end
On Player Join
local function run(Player)
local isPlayerInServer = true
local rewardValue = 0
local playerDataArrayWithBias
local playerDataArrayWithoutBias
local playerDataVectorWithBias
local playerDataVectorWithoutBias
local predictedTimeToLeave
local predictedProbabilityToLeave
local activateLeftToEarlyPredictionModel
local stayProbability
while isPlayerInServer do
playerDataArrayWithBias, playerDataArrayWithoutBias = getPlayerDataArrays()
snapshotData(playerDataArray)
playerDataVectorWithBias = {playerDataArrayWithBias}
predictedTimeToLeave = TimeToLeavePredictionModel:predict(playerDataVectorWithBias)[1][1]
predictedProbabilityToLeave = ProbabilityToLeavePredictionModel:predict(playerDataVectorWithBias)[1][1]
activateLeftToEarlyPredictionModel = (predictedProbabilityToLeave >= 0.5) or (predictedTimeToLeave <= 5)
if (activateLeftToEarlyPredictionModel) then
playerDataVectorWithoutBias = {playerDataArrayWithoutBias}
probabilityToStay = LeftToEarlyPredictionModel:predict(playerDataVectorWithoutBias)[1][1]
-- Let's reward the player for staying much more longer than our models' predictions.
if (probabilityToStay <= 0.1) then givePlayerReward(Player) end
end
task.wait(predictedTimeToLeave)
isPlayerInServer = checkIfPlayerIsInServer(Player)
end
end
On Player Leave
local timeToLeaveVector = {}
local probabilityToLeaveVector = {}
local probabilityToStayVector = {}
for i = 1, snapshotIndex, 1 do
local timeToLeave = os.time() - recordedTime[i]
local probabilityToLeave = 1 / timeToLeave
local probabilityToStay = 1 - probabilityToLeave
timeToLeaveVector[i] = {timeToLeave}
probabilityToLeaveVector[i] = {probabilityToLeave}
probabilityToStayVector[i] = {probabilityToStay}
end
TimeToLeavePredictionModel:train(playerDataMatrix, timeToLeaveVector)
ProbabilityToLeavePredictionModel:train(playerDataMatrix, probabilityToLeaveVector)
LeftToEarlyPredictionModel:train(playerDataMatrix, probabilityToStayVector)
-- Just getting our model parameters to save them
TimeToLeavePredictionModelParameters = TimeToLeavePredictionModel:getModelParameters(true)
ProbabilityToLeavePredictionModelParameters = ProbabilityToLeavePredictionModel:getModelParameters(true)
LeftToEarlyPredictionModelParameters = LeftToEarlyPredictionModel:getModelParameters(true)