Stress Systems - Creating Stress Tracking Model

Hello guys! Today, I will be showing you on how to create a stress-tracking model to determine the players’ stress level.

Currently, you need these to produce the model:

  • Any KalmanFilter model

  • A player data that is stored in matrix

Setting Up

Before we train our model, we will first need to construct a regression model as shown below.


local DataPredict = require(DataPredict)

local StressTrackingModel = DataPredict.Models.KalmanFilter.new({})

The Feature Matrix


-- We're just adding 1 here to add "bias".

local playerDataVector = {
    {
        1,
		timeSinceLastInput,
		numberOfConsecutiveInputs,
        actionsPerMinute,
        effectiveActionsPerMinute,
    }
}

Full Setup


local maximumStressScore = 100 -- This must be adjusted based on your data and your environment.

local adaptiveRate = 0.01 -- How fast thresholds adapt (lower = more stable).

local function onPlayerConnect(Player: Player)
	
	local isStressDetected = false
	
	local stressScore = 0

	local rollingCost = 0

	local adaptiveMean = 0

	local adaptiveVariance = 0

	local timeSinceLastWarned = 0
	
	local previousStateVector

	local currentStateVector
	
	local isIdle

	local costArray

	local cost
	
	local valueDifference
	
	local standardDeviationValue
	
	local lowerBoundRollingCostThreshold
	
	local upperBoundRollingCostThreshold
	
	local deviationValue

	InputRemoteEvent.OnClientEvent:Connect(function(Player)
		
		currentStateVector = getStateVector(Player, previousStateVector)
		
		isIdle = checkIfIsIdle(previousStateVector, currentStateVector)

		costArray = AnomalyDetectionModel:train(previousStateVector, currentStateVector)
		
		previousStateVector = currentStateVector

		cost = costArray[1]
		
		rollingCost = (rollingCostRate * rollingCost) + (rollingCostRateComplement * cost) -- Exponential smoothing.
		
		valueDifference = rollingCost - adaptiveMean
		
		adaptiveMean = adaptiveMean + (adaptiveRate * valueDifference)
		
		adaptiveVariance = (1 - adaptiveRate) * (adaptiveVariance + (adaptiveRate * math.pow(valueDifference, 2)))

		standardDeviationValue = math.sqrt(adaptiveVariance)
		
		lowerBoundRollingCostThreshold = adaptiveMean - (3 * standardDeviationValue)
		
		upperBoundRollingCostThreshold = adaptiveMean + (3 * standardDeviationValue)
		
		deviationValue = 0
		
		if (isIdle) then
			
			stressScore = math.max(0, stressScore - 1)
		
		elseif (rollingCost < lowerBoundRollingCostThreshold) then
			
			deviationValue = (lowerBoundRollingCostThreshold - rollingCost)
			
		elseif (rollingCost > upperBoundRollingCostThreshold) then

			deviationValue = (rollingCost - upperBoundRollingCostThreshold)

		else

			stressScore = math.max(0, stressScore - 1)

		end
		
		stressScore = stressScore + (deviationValue * 0.1)
		
		stressScore = math.max(0, stressScore - (0.05 * (1 - math.abs(deviationValue))))
		
		isStressDetected = (stressScore >= maximumStressScore)
		
		if (isStressDetected) and (timeSinceLastWarned <= 0) then
			
			timeSinceLastWarned = numberOfSecondsToResetCheatWarning
			
			warn(warningString:format(Player.Name, stressScore, rollingCost, cost))
			
		else
			
			timeSinceLastWarned = math.max(timeSinceLastWarned - delta, 0)
			
		end
	
	end)
	
end


This site uses Just the Docs, a documentation theme for Jekyll.