Skip to content

Optimisation has probably not converged to the maximum likelihood - Hessian is not positive definite #110

@diogoroicado

Description

@diogoroicado

Dear Dr. Jackson,

I am working on a credit card fraud detection project and encountered a challenge while estimating a multi-state model. My dataset, generated using Harris' Sparkov Data Generator (GitHub), includes 50 customers with highly variable transaction counts (ranging from 3,486 to 559 per customer).

For my analysis, I defined four states: 1 - Normal behavior, 2 - Suspicious activity, 3 - Fraud and 4 - Fraud network.

Given the nature of the problem, fraudulent transactions are rare, which I suspect is affecting model estimation. Below is my dataset with all engineered features:
data.csv

I first attempted a simple model without covariates:
Q1.crude <- crudeinits.msm(state ~ time, subject = cc_num, data = df_train, qmatrix = Q1)
[,1] [,2] [,3] [,4]
[1,] -26.71878 26.57784 0.140940 0.0000
[2,] 38.93366 -39.07305 0.139381 0.0000
[3,] 23.46347 13.46265 -52.696648 15.7705
[4,] 8.09495 6.25519 0.000000 -14.3501
Then, I attempted to fit the model using:
msm_baseline1 <- msm(state ~ time, subject = cc_num, data = df_train, qmatrix = Q1, gen.inits = TRUE, method = "BFGS", control = list(fnscale = 500, maxit = 500, reltol = 1e-16))
However, I received the following warning:
Warning message:
In msm(state ~ time, subject = cc_num, data = df_train, qmatrix = Q1, :
Optimisation has probably not converged to the maximum likelihood - Hessian is not positive definite.

I have reviewed your GitHub resources and manual, adjusting parameters such as maxit, fnscale, and rescaling time, but the issue persists.

Could the severe class imbalance be causing estimation issues?
Should I modify the transition matrix initialization or impose constraints?

I would greatly appreciate any guidance or recommendations on how to improve model estimation. Thank you for your time and for developing such an invaluable tool, which has been instrumental in my research.

Best regards

ps: I have rescaled the time feature by setting it to months - df_train <- df_train %>%
mutate(time = as.numeric(as.POSIXct(time, format="%Y-%m-%d %H:%M:%S", tz="UTC")), time = signif((time - min(time, na.rm = TRUE)) / (60 * 60 * 24 * 30), digits = 10))

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions