Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Aplica-se a: ✅Microsoft Fabric✅Azure Data Explorer✅Azure Monitor✅Microsoft Sentinel
Detecte a aparência de picos anômalos em variáveis numéricas em dados com carimbo de data/hora.
A função detect_anomalous_spike_fl() é uma UDF (função definida pelo usuário) que detecta a aparência de picos anômalos em variáveis numéricas - como quantidade de dados exfiltrados ou tentativas de entrada com falha - em dados com carimbo de data/hora, como logs de tráfego. No contexto de segurança cibernética, esses eventos podem ser suspeitos e indicar um possível ataque ou comprometimento.
O modelo de anomalias baseia-se em uma combinação de duas pontuações: pontuação Z (o número de desvios padrão acima da média) e pontuação Q (o número de intervalos interquantiles acima de um quantile alto). A pontuação Z é uma métrica simples e comum de exceção; A pontuação Q é baseada nas cercas de Tukey - mas estendemos a definição a quaisquer quantiles para mais controle. Escolher quantiles diferentes (por padrão, quantiles 95 e 25 são usados) permite detectar exceções mais significativas, melhorando assim a precisão. O modelo é criado com base em alguma variável numérica (como o número de tentativas de logon ou a quantidade de dados exfiltrados) e é calculado por escopo (como assinatura ou conta) e por entidade (como usuário ou dispositivo).
Depois de calcular as pontuações de um ponto de dados numérico de variação única e verificar outros requisitos (por exemplo, o número de dias ativos no período de treinamento no escopo está acima de um limite predefinido), verificamos se cada uma das pontuações está acima do limite predefinido. Nesse caso, um pico é detectado e o ponto de dados é sinalizado como anômalo. Dois modelos são criados: um para o nível de entidade (definido pelo parâmetro entityColumnName) - como usuário ou dispositivo por escopo (definido pelo parâmetro scopeColumnName) - como conta ou assinatura. O segundo modelo é criado para todo o escopo. A lógica de detecção de anomalias é executada para cada modelo e, se a anomalia for detectada em um deles, ela será mostrada. Por padrão, picos para cima são detectados; picos descendentes ('dips') também podem ser interessantes em alguns contextos e podem ser detectados adaptando a lógica.
A saída direta do modelo é uma pontuação de anomalias com base nas pontuações. A pontuação é monótona no intervalo de [0, 1], com 1 representando algo anômalo. Além da pontuação de anomalias, há um sinalizador binário para anomalias detectadas (controlada por um parâmetro de limite mínimo) e outros campos explicativos.
Observe que a função desconsidera a estrutura temporal da variável (principalmente para escalabilidade e explicabilidade). Se a variável tiver componentes temporais significativos , como tendência e sazonalidades, sugerimos considerar a função
Sintaxe
detect_anomalous_spike_fl(
numericColumnName, entityColumnName, scopeColumnName, timeColumnName, startTraining, startDetection, endDetection, [minTrainingDaysThresh], [lowPercentileForQscore], [highPercentileForQscore], [minSlicesPerEntity], [zScoreThreshEntity], [qScoreThreshEntity], [minNumValueThreshEntity], [minSlicesPerScope], [zScoreThreshScope], [qScoreThreshScope], [minNumValueThreshScope])
Saiba mais sobre convenções de sintaxe.
Parâmetros
| Nome | Tipo | Necessário | Descrição |
|---|---|---|---|
| numericColumnName | string |
✔️ | O nome da coluna da tabela de entrada que contém variável numérica para a qual os modelos de anomalias são calculados. |
| entityColumnName | string |
✔️ | O nome da coluna da tabela de entrada que contém os nomes ou IDs das entidades para as quais o modelo de anomalias é calculado. |
| scopeColumnName | string |
✔️ | O nome da coluna da tabela de entrada que contém a partição ou o escopo, de modo que um modelo de anomalias diferente seja criado para cada escopo. |
| timeColumnName | string |
✔️ | O nome da coluna da tabela de entrada que contém os carimbos de data/hora, que são usados para definir os períodos de treinamento e detecção. |
| startTraining | datetime |
✔️ | O início do período de treinamento para o modelo de anomalias. Seu final é definido pelo início do período de detecção. |
| startDetection | datetime |
✔️ | O início do período de detecção para detecção de anomalias. |
| endDetection | datetime |
✔️ | O fim do período de detecção para detecção de anomalias. |
| minTrainingDaysThresh | int |
O número mínimo de dias no período de treinamento que existe um escopo para calcular anomalias. Se estiver abaixo do limite, o escopo será considerado muito novo e desconhecido, portanto, as anomalias não serão calculadas. O valor padrão é 14. | |
| lowPercentileForQscore | real |
Um número no intervalo [0,0,1,0] que representa o percentil a ser calculado como um limite baixo para a pontuação Q. Nas cercas de Tukey, 0,25 é usado. O valor padrão é 0,25. Escolher um percentil mais baixo melhora a precisão à medida que anomalias mais significativas são detectadas. | |
| highPercentileForQscore | real |
Um número no intervalo [0,0,1,0] que representa o percentil a ser calculado como limite alto para pontuação Q. Nas cercas de Tukey, 0,75 é usado. O valor padrão é 0,9. Escolher um percentil mais alto melhora a precisão à medida que anomalias mais significativas são detectadas. | |
| minSlicesPerEntity | int |
O limite mínimo de 'fatias' (por exemplo, dias) a existir em uma entidade antes que o modelo de anomalia seja criado para ele. Se o número estiver abaixo do limite, a entidade será considerada muito nova e instável. O valor padrão é 20. | |
| zScoreThreshEntity | real |
O limite mínimo para que a pontuação Z no nível da entidade (número de desvios padrão acima da média) seja sinalizada como anomalia. Ao escolher valores mais altos, apenas anomalias mais significativas são detectadas. O valor padrão é 3.0. | |
| qScoreThreshEntity | real |
O limite mínimo para que a pontuação Q no nível da entidade (número de intervalos interquantiles acima do quantile alto) seja sinalizada como anomalia. Ao escolher valores mais altos, apenas anomalias mais significativas são detectadas. O valor padrão é 2.0. | |
| minNumValueThreshEntity | long |
O limite mínimo para que a variável numérica seja sinalizada como anomalia para uma entidade. Isso é útil para filtrar casos em que um valor é anormal estatisticamente (pontuação Z alta e pontuação em Q), mas o valor em si é muito pequeno para ser interessante. O valor padrão é 0. | |
| minSlicesPerScope | int |
O limite mínimo de 'fatias' (por exemplo, dias) a existir em um escopo antes que o modelo de anomalia seja criado para ele. Se o número estiver abaixo do limite, o escopo será considerado muito novo e instável. O valor padrão é 20. | |
| zScoreThreshScope | real |
O limite mínimo para pontuação Z no nível do escopo (número de desvios padrão acima da média) a ser sinalizado como anomalia. Ao escolher valores mais altos, apenas anomalias mais significativas são detectadas. O valor padrão é 3.0. | |
| qScoreThreshScope | real |
O limite mínimo para que a pontuação Q no nível do escopo (número de intervalos interquantiles acima do quantile alto) seja sinalizada como anomalia. Ao escolher valores mais altos, apenas anomalias mais significativas são detectadas. O valor padrão é 2.0. | |
| minNumValueThreshScope | long |
O limite mínimo para que a variável numérica seja sinalizada como anomalia para um escopo. Isso é útil para filtrar casos em que um valor é anormal estatisticamente (pontuação Z alta e pontuação em Q), mas o valor em si é muito pequeno para ser interessante. O valor padrão é 0. |
Definição de função
Você pode definir a função inserindo seu código como uma função definida por consulta ou criando-a como uma função armazenada em seu banco de dados, da seguinte maneira:
Defina a função usando a instrução let a seguir. Nenhuma permissão é necessária.
Importante
Uma instrução não pode ser executada por conta própria. Ele deve ser seguido por uma instrução de expressão tabular . Para executar um exemplo de trabalho de detect_anomalous_spike_fl(), consulte Exemplo.
let detect_anomalous_spike_fl = (T:(*), numericColumnName:string, entityColumnName:string, scopeColumnName:string
, timeColumnName:string, startTraining:datetime, startDetection:datetime, endDetection:datetime, minTrainingDaysThresh:int = 14
, lowPercentileForQscore:real = 0.25, highPercentileForQscore:real = 0.9
, minSlicesPerEntity:int = 20, zScoreThreshEntity:real = 3.0, qScoreThreshEntity:real = 2.0, minNumValueThreshEntity:long = 0
, minSlicesPerScope:int = 20, zScoreThreshScope:real = 3.0, qScoreThreshScope:real = 2.0, minNumValueThreshScope:long = 0)
{
// pre-process the input data by adding standard column names and dividing to datasets
let timePeriodBinSize = 'day'; // we assume a reasonable bin for time is day
let processedData = (
T
| extend scope = column_ifexists(scopeColumnName, '')
| extend entity = column_ifexists(entityColumnName, '')
| extend numVec = tolong(column_ifexists(numericColumnName, 0))
| extend sliceTime = todatetime(column_ifexists(timeColumnName, ''))
| where isnotempty(scope) and isnotempty(sliceTime)
| extend dataSet = case((sliceTime >= startTraining and sliceTime < startDetection), 'trainSet'
, sliceTime >= startDetection and sliceTime <= endDetection, 'detectSet'
, 'other')
| where dataSet in ('trainSet', 'detectSet')
);
let aggregatedCandidateScopeData = (
processedData
| summarize firstSeenScope = min(sliceTime), lastSeenScope = max(sliceTime) by scope
| extend slicesInTrainingScope = datetime_diff(timePeriodBinSize, startDetection, firstSeenScope)
| where slicesInTrainingScope >= minTrainingDaysThresh and lastSeenScope >= startDetection
);
let entityModelData = (
processedData
| join kind = inner (aggregatedCandidateScopeData) on scope
| where dataSet == 'trainSet'
| summarize countSlicesEntity = dcount(sliceTime), avgNumEntity = avg(numVec), sdNumEntity = stdev(numVec)
, lowPrcNumEntity = percentile(numVec, lowPercentileForQscore), highPrcNumEntity = percentile(numVec, highPercentileForQscore)
, firstSeenEntity = min(sliceTime), lastSeenEntity = max(sliceTime)
by scope, entity
| extend slicesInTrainingEntity = datetime_diff(timePeriodBinSize, startDetection, firstSeenEntity)
);
let scopeModelData = (
processedData
| join kind = inner (aggregatedCandidateScopeData) on scope
| where dataSet == 'trainSet'
| summarize countSlicesScope = dcount(sliceTime), avgNumScope = avg(numVec), sdNumScope = stdev(numVec)
, lowPrcNumScope = percentile(numVec, lowPercentileForQscore), highPrcNumScope = percentile(numVec, highPercentileForQscore)
by scope
);
let resultsData = (
processedData
| where dataSet == 'detectSet'
| join kind = inner (aggregatedCandidateScopeData) on scope
| join kind = leftouter (entityModelData) on scope, entity
| join kind = leftouter (scopeModelData) on scope
| extend zScoreEntity = iff(countSlicesEntity >= minSlicesPerEntity, round((toreal(numVec) - avgNumEntity)/(sdNumEntity + 1), 2), 0.0)
, qScoreEntity = iff(countSlicesEntity >= minSlicesPerEntity, round((toreal(numVec) - highPrcNumEntity)/(highPrcNumEntity - lowPrcNumEntity + 1), 2), 0.0)
, zScoreScope = iff(countSlicesScope >= minSlicesPerScope, round((toreal(numVec) - avgNumScope)/(sdNumScope + 1), 2), 0.0)
, qScoreScope = iff(countSlicesScope >= minSlicesPerScope, round((toreal(numVec) - highPrcNumScope)/(highPrcNumScope - lowPrcNumScope + 1), 2), 0.0)
| extend isSpikeOnEntity = iff((slicesInTrainingEntity >= minTrainingDaysThresh and zScoreEntity > zScoreThreshEntity and qScoreEntity > qScoreThreshEntity and numVec >= minNumValueThreshEntity), 1, 0)
, entityHighBaseline= round(max_of((avgNumEntity + sdNumEntity), highPrcNumEntity), 2)
, isSpikeOnScope = iff((countSlicesScope >= minTrainingDaysThresh and zScoreScope > zScoreThreshScope and qScoreScope > qScoreThreshScope and numVec >= minNumValueThreshScope), 1, 0)
, scopeHighBaseline = round(max_of((avgNumEntity + 2 * sdNumEntity), highPrcNumScope), 2)
| extend entitySpikeAnomalyScore = iff(isSpikeOnEntity == 1, round(1.0 - 0.25/(max_of(zScoreEntity, qScoreEntity)),4), 0.00)
, scopeSpikeAnomalyScore = iff(isSpikeOnScope == 1, round(1.0 - 0.25/(max_of(zScoreScope, qScoreScope)), 4), 0.00)
| where isSpikeOnEntity == 1 or isSpikeOnScope == 1
| extend avgNumEntity = round(avgNumEntity, 2), sdNumEntity = round(sdNumEntity, 2)
, avgNumScope = round(avgNumScope, 2), sdNumScope = round(sdNumScope, 2)
| project-away entity1, scope1, scope2, scope3
| extend anomalyType = iff(isSpikeOnEntity == 1, strcat('spike_', entityColumnName), strcat('spike_', scopeColumnName)), anomalyScore = max_of(entitySpikeAnomalyScore, scopeSpikeAnomalyScore)
| extend anomalyExplainability = iff(isSpikeOnEntity == 1
, strcat('The value of numeric variable ', numericColumnName, ' for ', entityColumnName, ' ', entity, ' is ', numVec, ', which is abnormally high for this '
, entityColumnName, ' at this ', scopeColumnName
, '. Based on observations from last ' , slicesInTrainingEntity, ' ', timePeriodBinSize, 's, the expected baseline value is below ', entityHighBaseline, '.')
, strcat('The value of numeric variable ', numericColumnName, ' on ', scopeColumnName, ' ', scope, ' is ', numVec, ', which is abnormally high for this '
, scopeColumnName, '. Based on observations from last ' , slicesInTrainingScope, ' ', timePeriodBinSize, 's, the expected baseline value is below ', scopeHighBaseline, '.'))
| extend anomalyState = iff(isSpikeOnEntity == 1
, bag_pack('avg', avgNumEntity, 'stdev', sdNumEntity, strcat('percentile_', lowPercentileForQscore), lowPrcNumEntity, strcat('percentile_', highPercentileForQscore), highPrcNumEntity)
, bag_pack('avg', avgNumScope, 'stdev', sdNumScope, strcat('percentile_', lowPercentileForQscore), lowPrcNumScope, strcat('percentile_', highPercentileForQscore), highPrcNumScope))
| project-away lowPrcNumEntity, highPrcNumEntity, lowPrcNumScope, highPrcNumScope
);
resultsData
};
// Write your query to use the function here.
Exemplo
O exemplo a seguir usa o operador de invocação para executar a função.
Para usar uma função definida por consulta, invoque-a após a definição da função inserida.
executar o de consulta
let detect_anomalous_spike_fl = (T:(*), numericColumnName:string, entityColumnName:string, scopeColumnName:string
, timeColumnName:string, startTraining:datetime, startDetection:datetime, endDetection:datetime, minTrainingDaysThresh:int = 14
, lowPercentileForQscore:real = 0.25, highPercentileForQscore:real = 0.9
, minSlicesPerEntity:int = 20, zScoreThreshEntity:real = 3.0, qScoreThreshEntity:real = 2.0, minNumValueThreshEntity:long = 0
, minSlicesPerScope:int = 20, zScoreThreshScope:real = 3.0, qScoreThreshScope:real = 2.0, minNumValueThreshScope:long = 0)
{
// pre-process the input data by adding standard column names and dividing to datasets
let timePeriodBinSize = 'day'; // we assume a reasonable bin for time is day
let processedData = (
T
| extend scope = column_ifexists(scopeColumnName, '')
| extend entity = column_ifexists(entityColumnName, '')
| extend numVec = tolong(column_ifexists(numericColumnName, 0))
| extend sliceTime = todatetime(column_ifexists(timeColumnName, ''))
| where isnotempty(scope) and isnotempty(sliceTime)
| extend dataSet = case((sliceTime >= startTraining and sliceTime < startDetection), 'trainSet'
, sliceTime >= startDetection and sliceTime <= endDetection, 'detectSet'
, 'other')
| where dataSet in ('trainSet', 'detectSet')
);
let aggregatedCandidateScopeData = (
processedData
| summarize firstSeenScope = min(sliceTime), lastSeenScope = max(sliceTime) by scope
| extend slicesInTrainingScope = datetime_diff(timePeriodBinSize, startDetection, firstSeenScope)
| where slicesInTrainingScope >= minTrainingDaysThresh and lastSeenScope >= startDetection
);
let entityModelData = (
processedData
| join kind = inner (aggregatedCandidateScopeData) on scope
| where dataSet == 'trainSet'
| summarize countSlicesEntity = dcount(sliceTime), avgNumEntity = avg(numVec), sdNumEntity = stdev(numVec)
, lowPrcNumEntity = percentile(numVec, lowPercentileForQscore), highPrcNumEntity = percentile(numVec, highPercentileForQscore)
, firstSeenEntity = min(sliceTime), lastSeenEntity = max(sliceTime)
by scope, entity
| extend slicesInTrainingEntity = datetime_diff(timePeriodBinSize, startDetection, firstSeenEntity)
);
let scopeModelData = (
processedData
| join kind = inner (aggregatedCandidateScopeData) on scope
| where dataSet == 'trainSet'
| summarize countSlicesScope = dcount(sliceTime), avgNumScope = avg(numVec), sdNumScope = stdev(numVec)
, lowPrcNumScope = percentile(numVec, lowPercentileForQscore), highPrcNumScope = percentile(numVec, highPercentileForQscore)
by scope
);
let resultsData = (
processedData
| where dataSet == 'detectSet'
| join kind = inner (aggregatedCandidateScopeData) on scope
| join kind = leftouter (entityModelData) on scope, entity
| join kind = leftouter (scopeModelData) on scope
| extend zScoreEntity = iff(countSlicesEntity >= minSlicesPerEntity, round((toreal(numVec) - avgNumEntity)/(sdNumEntity + 1), 2), 0.0)
, qScoreEntity = iff(countSlicesEntity >= minSlicesPerEntity, round((toreal(numVec) - highPrcNumEntity)/(highPrcNumEntity - lowPrcNumEntity + 1), 2), 0.0)
, zScoreScope = iff(countSlicesScope >= minSlicesPerScope, round((toreal(numVec) - avgNumScope)/(sdNumScope + 1), 2), 0.0)
, qScoreScope = iff(countSlicesScope >= minSlicesPerScope, round((toreal(numVec) - highPrcNumScope)/(highPrcNumScope - lowPrcNumScope + 1), 2), 0.0)
| extend isSpikeOnEntity = iff((slicesInTrainingEntity >= minTrainingDaysThresh and zScoreEntity > zScoreThreshEntity and qScoreEntity > qScoreThreshEntity and numVec >= minNumValueThreshEntity), 1, 0)
, entityHighBaseline= round(max_of((avgNumEntity + sdNumEntity), highPrcNumEntity), 2)
, isSpikeOnScope = iff((countSlicesScope >= minTrainingDaysThresh and zScoreScope > zScoreThreshScope and qScoreScope > qScoreThreshScope and numVec >= minNumValueThreshScope), 1, 0)
, scopeHighBaseline = round(max_of((avgNumEntity + 2 * sdNumEntity), highPrcNumScope), 2)
| extend entitySpikeAnomalyScore = iff(isSpikeOnEntity == 1, round(1.0 - 0.25/(max_of(zScoreEntity, qScoreEntity)),4), 0.00)
, scopeSpikeAnomalyScore = iff(isSpikeOnScope == 1, round(1.0 - 0.25/(max_of(zScoreScope, qScoreScope)), 4), 0.00)
| where isSpikeOnEntity == 1 or isSpikeOnScope == 1
| extend avgNumEntity = round(avgNumEntity, 2), sdNumEntity = round(sdNumEntity, 2)
, avgNumScope = round(avgNumScope, 2), sdNumScope = round(sdNumScope, 2)
| project-away entity1, scope1, scope2, scope3
| extend anomalyType = iff(isSpikeOnEntity == 1, strcat('spike_', entityColumnName), strcat('spike_', scopeColumnName)), anomalyScore = max_of(entitySpikeAnomalyScore, scopeSpikeAnomalyScore)
| extend anomalyExplainability = iff(isSpikeOnEntity == 1
, strcat('The value of numeric variable ', numericColumnName, ' for ', entityColumnName, ' ', entity, ' is ', numVec, ', which is abnormally high for this '
, entityColumnName, ' at this ', scopeColumnName
, '. Based on observations from last ' , slicesInTrainingEntity, ' ', timePeriodBinSize, 's, the expected baseline value is below ', entityHighBaseline, '.')
, strcat('The value of numeric variable ', numericColumnName, ' on ', scopeColumnName, ' ', scope, ' is ', numVec, ', which is abnormally high for this '
, scopeColumnName, '. Based on observations from last ' , slicesInTrainingScope, ' ', timePeriodBinSize, 's, the expected baseline value is below ', scopeHighBaseline, '.'))
| extend anomalyState = iff(isSpikeOnEntity == 1
, bag_pack('avg', avgNumEntity, 'stdev', sdNumEntity, strcat('percentile_', lowPercentileForQscore), lowPrcNumEntity, strcat('percentile_', highPercentileForQscore), highPrcNumEntity)
, bag_pack('avg', avgNumScope, 'stdev', sdNumScope, strcat('percentile_', lowPercentileForQscore), lowPrcNumScope, strcat('percentile_', highPercentileForQscore), highPrcNumScope))
| project-away lowPrcNumEntity, highPrcNumEntity, lowPrcNumScope, highPrcNumScope
);
resultsData
};
let detectPeriodStart = datetime(2022-04-30 05:00:00.0000000);
let trainPeriodStart = datetime(2022-03-01 05:00);
let names = pack_array("Admin", "Dev1", "Dev2", "IT-support");
let countNames = array_length(names);
let testData = range t from 1 to 24*60 step 1
| extend timeSlice = trainPeriodStart + 1h * t
| extend countEvents = round(2*rand() + iff((t/24)%7>=5, 10.0, 15.0) - (((t%24)/10)*((t%24)/10)), 2) * 100
| extend userName = tostring(names[toint(rand(countNames))])
| extend deviceId = hash_md5(rand())
| extend accountName = iff(((rand() < 0.2) and (timeSlice < detectPeriodStart)), 'testEnvironment', 'prodEnvironment')
| extend userName = iff(timeSlice == detectPeriodStart, 'H4ck3r', userName)
| extend countEvents = iff(timeSlice == detectPeriodStart, 3*countEvents, countEvents)
| sort by timeSlice desc
;
testData
| invoke detect_anomalous_spike_fl(numericColumnName = 'countEvents'
, entityColumnName = 'userName'
, scopeColumnName = 'accountName'
, timeColumnName = 'timeSlice'
, startTraining = trainPeriodStart
, startDetection = detectPeriodStart
, endDetection = detectPeriodStart
)
de saída
| t | timeSlice | countEvents | userName | deviceId | accountName | âmbito | entidade | numVec | sliceTime | Dataset | firstSeenScope | lastSeenScope | slicesInTrainingScope | countSlicesEntity | avgNumEntity | sdNumEntity | firstSeenEntity | lastSeenEntity | slicesInTrainingEntity | countSlicesScope | avgNumScope | sdNumScope | zScoreEntity | qScoreEntity | zScoreScope | qScoreScope | isSpikeOnEntity | entityHighBaseline | isSpikeOnScope | scopeHighBaseline | entitySpikeAnomalyScore | scopeSpikeAnomalyScore | anomalyType | anomalyScore | anomalyExplainability | anomalyState |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1440 | 2022-04-30 05:00:00.0000000 | 5079 | H4ck3r | 9e8e151aced5a64938b93ee0c13fe940 | prodEnvironment | prodEnvironment | H4ck3r | 5079 | 2022-04-30 05:00:00.0000000 | detectSet | 2022-03-01 08:00:00.0000000 | 2022-04-30 05:00:00.0000000 | 60 | 1155 | 1363.22 | 267.51 | 0 | 0 | 13.84 | 185.46 | 0 | 1 | 628 | 0 | 0.9987 | spike_accountName | 0.9987 | O valor de countEvents de variável numérica no accountName prodEnvironment é 5079, que é anormalmente alto para este accountName. Com base nas observações dos últimos 60 dias, o valor de linha de base esperado está abaixo de 628,0. | {"avg": 1363.22,"stdev": 267.51,"percentile_0.25": 605,"percentile_0.9": 628} |
A saída da execução da função são as linhas no conjunto de dados de detecção que foram marcadas como picos anômalos nos níveis de escopo ou entidade. Alguns outros campos são adicionados para maior clareza:
-
dataSet: conjunto de dados atual (é sempredetectSet). -
firstSeenScope: carimbo de data/hora quando o escopo foi visto pela primeira vez. -
lastSeenScope: carimbo de data/hora quando o escopo foi visto pela última vez. -
slicesInTrainingScope: número de fatias (por exemplo, dias) que o escopo existe no conjunto de dados de treinamento. -
countSlicesEntity: número de fatias (por exemplo, dias) que a entidade existe no escopo. -
avgNumEntity: média da variável numérica no conjunto de treinamento por entidade no escopo. -
sdNumEntity: desvio padrão da variável numérica no conjunto de treinamento por entidade no escopo. -
firstSeenEntity: carimbo de data/hora quando a entidade foi vista pela primeira vez no escopo. -
lastSeenEntity: carimbo de data/hora quando a entidade foi vista pela última vez no escopo. -
slicesInTrainingEntity: número de fatias (por exemplo, dias) que a entidade existe no escopo no conjunto de dados de treinamento. -
countSlicesScope: número de fatias (por exemplo, dias) que o escopo existe. -
avgNumScope: média da variável numérica no conjunto de treinamento por escopo. -
sdNumScope: desvio padrão da variável numérica no conjunto de treinamento por escopo. -
zScoreEntity: pontuação Z para o valor atual da variável numérica com base no modelo de entidade. -
qScoreEntity: pontuação Q para o valor atual da variável numérica com base no modelo de entidade. -
zScoreScope: pontuação Z para o valor atual da variável numérica com base no modelo de escopo. -
qScoreScope: pontuação Q para o valor atual da variável numérica com base no modelo de escopo. -
isSpikeOnEntity: sinalizador binário para pico anormal com base no modelo de entidade. -
entityHighBaseline: linha de base alta esperada para valores de variável numérica com base no modelo de entidade. -
isSpikeOnScope: sinalizador binário para pico anormal com base no modelo de escopo. -
scopeHighBaseline: linha de base alta esperada para valores de variável numérica com base no modelo de escopo. -
entitySpikeAnomalyScore: pontuação de anomalias para o pico com base no modelo de entidade; um número no intervalo [0,1], valores mais altos que significam mais anomalias. -
scopeSpikeAnomalyScore: pontuação de anomalias para o pico com base no modelo de escopo; um número no intervalo [0,1], valores mais altos que significam mais anomalias. -
anomalyType: mostra o tipo de anomalia (útil ao executar várias lógicas de detecção de anomalias juntas). -
anomalyScore: pontuação de anomalias para o pico com base no modelo escolhido. -
anomalyExplainability: wrapper textual para anomalia gerada e sua explicação. -
anomalyState: recipiente de métricas do modelo escolhido (média, desvio padrão e percentis) que descreve o modelo.
No exemplo acima, executar essa função na variável countEvents usando o usuário como entidade e conta como escopo com parâmetros padrão detecta um pico no nível do escopo. Como o usuário 'H4ck3r' não tem dados suficientes no período de treinamento, a anomalia não é calculada para o nível de entidade e todos os campos relevantes estão vazios. A anomalia no nível do escopo tem uma pontuação de anomalias de 0,998, o que significa que esse pico é anômalo para o escopo.
Se aumentarmos qualquer um dos limites mínimos alto o suficiente, nenhuma anomalia será detectada, pois os requisitos seriam muito altos.
A saída mostra as linhas com picos anômalos junto com campos explicativos em formato padronizado. Esses campos são úteis para investigar a anomalia e para executar a detecção de pico anômalo em várias variáveis numéricas ou executar outros algoritmos juntos.
O uso sugerido no contexto de segurança cibernética está executando a função em variáveis numéricas significativas (quantidades de dados baixados, contagens de arquivos carregados ou tentativas de entrada com falha) por escopos significativos (como assinatura em contas) e entidades (como usuários ou dispositivos). Um pico anormal detectado significa que o valor numérico é maior do que o esperado nesse escopo ou entidade e pode ser suspeito.