Source code for detector.plugins.domainator_utils
import numpy as np
import itertools
import pandas as pd
import pylcs
import Levenshtein
from src.base.log_config import get_logger
module_name = "data_analysis.detector"
logger = get_logger(module_name)
DOMAINATOR_FEATURE_COLUMNS = [
"levenshtein",
"jaro",
"jaro_reversed",
"jaro_winkler",
"jaro_winkler_reversed",
"lcs_sequence",
"lcs_string",
]
[docs]
def strip_domain(query: str):
"""Extract the domain name from the message for the window grouping
Currently does not differentiate between messages coming from
different users.
Returns:
str: Domain name string that the window will be grouped by
"""
query = query.strip(".")
query = query.split(".")
domain = ""
if len(query) >= 2:
domain = query[-2]
return domain
[docs]
def get_domainator_features(queries: list) -> pd.DataFrame:
"""Extracts feature vector from domain name for ML model inference.
Computes various statistical and linguistic features from the domain name
including label lengths, character frequencies, entropy measures, and
counts of different character types across domain name levels.
Args:
queries (list): List of query strings to extract features from.
Returns:
pandas.DataFrame: Feature vector ready for ML model prediction.
"""
queries = [query.strip(".") for query in queries]
subdomains = [".".join(domain.split(".")[:-2]) for domain in queries]
metrics = {column: [] for column in DOMAINATOR_FEATURE_COLUMNS}
# if subdomains:
cartesian = list(itertools.combinations(subdomains, 2))
metrics["levenshtein"] = np.mean(
[Levenshtein.ratio(product[0], product[1]) for product in cartesian]
)
metrics["jaro"] = np.mean(
[Levenshtein.jaro(product[0], product[1]) for product in cartesian]
)
metrics["jaro_reversed"] = np.mean(
[Levenshtein.jaro(product[0][::-1], product[1][::-1]) for product in cartesian]
)
metrics["jaro_winkler"] = np.mean(
[
Levenshtein.jaro_winkler(product[0], product[1], prefix_weight=0.2)
for product in cartesian
]
)
metrics["jaro_winkler_reversed"] = np.mean(
[
Levenshtein.jaro_winkler(
product[0][::-1], product[1][::-1], prefix_weight=0.2
)
for product in cartesian
]
)
metrics["lcs_sequence"] = np.mean(
[
(
pylcs.lcs_sequence_length(product[0], product[1])
/ ((len(product[0]) + len(product[1])) / 2)
if len(product[0]) and len(product[1])
else 0.0
)
for product in cartesian
]
)
metrics["lcs_string"] = np.mean(
[
(
pylcs.lcs_string_length(product[0], product[1])
/ ((len(product[0]) + len(product[1])) / 2)
if len(product[0]) and len(product[1])
else 0.0
)
for product in cartesian
]
)
return pd.DataFrame(
[[metrics[column] for column in DOMAINATOR_FEATURE_COLUMNS]],
columns=DOMAINATOR_FEATURE_COLUMNS,
)