Генерация транзакций в рамках compromised client фрода¶

  • ноутбуки лучше просматривать на Github pages, т.к. при просмотре прямо в репозитории могут быть проблемы с отображением, например, обрезка вывода с широкими датафреймами. Если в адресной строке браузера есть iaroslav-dzh.github.io, то вы уже на Github pages.
    Ссылки:
    • Ссылка на этот ноутбук
    • Ссылка на страницу генератора где есть все ноутбуки

Что подразумевается под compromised client фродом

  • транзакции покупок клиентов, которые были скомпрометированы - условно говоря скомпрометированы их карты или аккаунты ДБО т.е. кто-то посторонний совершает онлайн или оффлайн покупки от лица клиентов
  • транзакции генерируются, чтобы попадать по логике под какое-либо антифрод правило в рамках compromised фрода, напр.: резкая смена гео, покупка с другого ip и устройства и т.п.

Информация о ноутбуке

  • в этом ноутбуке демонстрация основных функций и классов относящихся к генерации compromised client фрода
  • где-то будет просто объяснение основной логики функции/класса, где-то также демонстрация работы
  • в compromised фроде будут только покупки, переводов пока не будет
  • в целом то, что генерируется в рамках compromised фрода можно увидеть почти в конце ноутбука под заголовком Функция генерации нескольких фрод транзакций gen_multi_fraud_txns
In [1]:
import pandas as pd
import numpy as np
import os
import pyarrow
import yaml
from data_generator.general_time import *
from data_generator.utils import load_configs, build_transaction, create_txns_df
In [2]:
np.set_printoptions(suppress=True)
pd.set_option('display.max_columns', None)
In [3]:
os.chdir("..")
os.getcwd()
Out[3]:
'C:\\Users\\iaros\\My_documents\\Education\\projects\\fraud_detection_01'
In [4]:
# Базовые конфиги
base_cfg = load_configs("./config/base.yaml")
# Настройки легальных транзакций
legit_cfg = load_configs("./config/legit.yaml")
# Общие настройки фрода
fraud_cfg = load_configs("./config/fraud.yaml")
# Настройки compromised client фрода
compr_cfg = load_configs("./config/compr.yaml")
# Настройки времени
time_cfg = load_configs("./config/time.yaml") 

# Пути к файлам
data_paths = base_cfg["data_paths"]



Создание конфиг класса с конфигами и данными для генерации¶



1. Конструктор конфиг класса ComprConfigBuilder¶

  • модуль data_generator.fraud.compr.build.config. Ссылка на исходный код в Github
  • создает объект CompPurchFraudCfg - содержащий конфиги и данные для генерации транзакций
  • Смысл такой же как у конфиг билдера для легальных транзакций:
    • Принимает на вход словари с данными из конфиг файлов и путь к директории текущего запуска для создания объекта
    • Метод build_cfg() создает объект конфиг класса compromised client fraud транзакций с данными и конфигами для генерации транзакций, например:
      • датафреймами с данными: timestamp-ы для семплирования времени, данные выбранных клиентов, мерчанты, фрод ip адреса, фрод девайсы; путями к директориям для записи файлов

Путь к директории для файлов текущего запуска генерации возьмем из прошлого ноутбука с легальными транзакциями т.к. у генератора в целом каскадный процесс генерации и генерация идет поэтапно: легальные, compromised фрод, дропы распределители, дропы покупатели. И каждый этап в разной степени зависит от предыдущего. В текущем случае для compromised фрода обязательно наличие созданных ранее легальных транзакций и семпла клиентов взятого под создание тех легальных транз-ций, т.к. от легальных транзакций берется время для расчета времени фрод транзакции, а от клиентов берется семпл под compromised фрод.

In [7]:
run_dir = './data/generated/history/generation_run_2025-07-25_121029'
In [8]:
# Создадим объект конфиг класса при помощи билдера. Будем использовать конфиг класс дальше
from data_generator.fraud.compr.build.config import ComprConfigBuilder

cfg_builder = ComprConfigBuilder(base_cfg=base_cfg, legit_cfg=legit_cfg, time_cfg=time_cfg, \
                                 fraud_cfg=fraud_cfg, compr_cfg=compr_cfg, run_dir=run_dir)
configs = cfg_builder.build_cfg()
In [9]:
# Проверка и демонстрация конфиг класса. Клиенты семплированные под фрод
configs.clients.head(2)
Out[9]:
client_id city_id birth_date sex region city timezone lat lon population home_ip
0 1114 59 2005-06-12 male Краснодарский Краснодар UTC+3 45.040235 38.976080 744933 2.60.4.36
1 1125 9 1959-03-24 female Кемеровская Новокузнецк UTC+7 53.794276 87.214405 547885 2.60.4.47
In [8]:
# Фрод ip адреса, которые будут использоваться для онлайн транзакций
configs.fraud_ips.head(2)
Out[8]:
city lat lon fraud_ip
0 Москва 55.753879 37.620373 5.3.252.223
1 Санкт-Петербург 59.939125 30.315822 5.3.252.224
In [9]:
# Фрод девайсы, которые будут использоваться для онлайн транзакций
configs.fraud_devices.head(2)
Out[9]:
device_id platform
0 9670 Windows
1 9671 Windows




Генерация времени¶



1. Функция генерации времени generate_time_fast_geo_jump¶

  • для фрод кейсов в рамках правил резкой смены гео клиентом: fast_geo_change и fast_geo_change_online
  • модуль data_generator.fraud.compr.time. Ссылка на исходный код в Github

Условия

  1. Подразумевается что у клиента не было фрода

Основная логика функции

  1. Принимает на вход:
    • время последней легальной транзакций
    • крачайшую дистанцию между координатами последней легальной транз-ции и координатами текущей транзакции. Подразумевается что координаты текущей транзакции генерируются до вызова это функции и также до вызова считается дистанция между координатами
    • дистанцию между координатами последней легальной транзакции и текущей транзакции
    • пороговое значение максимальной допустимой скорости перемещения клиента между совершением транзакций км/ч. Все что строго выше по скорости - фрод. Пороговое значение будет браться из конфига compr.yaml, вне функции.
  2. На основании дистанции между координатами и порога по скорости задается случайная скорость перемещения выше указанного порога, чтобы попасть под фрод.
  3. Дистанция делится на полученную скорость для получения разницы во времени между последней легальной и текущей фрод транзакциями
  4. Полученная разница прибавляется ко времени последней легальной транзакции. Это и будет временем фрод транзакции

Демонстрация¶

In [15]:
from data_generator.fraud.compr.time import generate_time_fast_geo_jump

Создадим датафрейм с дистанциями, колонками под время в минутах и под время последней легальной транзакции. Будем проходить в цикле через этот датафрейм и генерировать время каждый раз, чтобы была выборка из нескольких вариантов

In [13]:
# 4 варианта дистанции между транзакциями в километрах
distances = pd.DataFrame({"distance":[800, 1200, 5000, 7500]})
distances["minutes"] = 0

# Время последней легальной транзакции на основании которого будет рассчитываться время для фрода
last_time = pd.to_datetime("2023-09-20 09:14:00", format="%Y-%m-%d %H:%M:%S")
last_unix = pd_timestamp_to_unix(last_time)
distances["last_unix"] = last_unix

distances
Out[13]:
distance minutes last_unix
0 800 0 1695201240
1 1200 0 1695201240
2 5000 0 1695201240
3 7500 0 1695201240

Вызов функции в цикле и запись созданного времени

In [18]:
for row in distances.itertuples():
    _, txn_unix = generate_time_fast_geo_jump(last_txn_unix=last_unix, geo_distance=row.distance, threshold=800)
    distances.loc[row.Index, "txn_unix"] = txn_unix

# Получившаяся разнциа в минутах
distances["time_diff"] = (distances["txn_unix"] - distances["last_unix"]) // 60

# Можно увидеть заданную дистанцию и время за которое клиент "переместился"
distances[["distance", "time_diff"]]
Out[18]:
distance time_diff
0 800 20.0
1 1200 13.0
2 5000 53.0
3 7500 127.0


2. Функция генерации времени транзакции для симуляции участившихся транзакций gen_time_for_frequent_trans¶

  • для фрод кейсов когда транзакции клиента резко участились - серия из нескольких частых транзакций подряд - правило trans_freq_increase
  • модуль data_generator.fraud.compr.time. Ссылка на исходный код в Github

Условия

  1. Подразумевается что время перввой фрод транзакции в серии участившихся транзакций создается функцией derive_from_last_time которая будет объеяснена дальше в ноутбуке, а эта функция создает время для всех последующих транзакций в серии, это как бы один фрод кейс все вместе.

Основная логика функции

  1. Берется время предыдущей транзакции
  2. Создается случайная разница времени, но в рамках заданных минимума и максимума, указанных в конфигах в compr.yaml
  3. Ко времени предыдущей транзакции прибавляется эта случайная разница

Демонстрация¶

In [19]:
from data_generator.fraud.compr.time import gen_time_for_frequent_trans

Тест gen_time_for_frequent_trans в цикле

In [26]:
transactions = create_txns_df(base_cfg["txns_df"])
In [28]:
# Датафрейм со временем одной условно легальной транзакции
last_time = pd.to_datetime("2023-09-20 09:14:00", format="%Y-%m-%d %H:%M:%S")
last_unix = pd_timestamp_to_unix(last_time)

trans_test_freq_time = transactions.copy().loc[:, ['txn_time', 'unix_time', "is_fraud"]]
trans_test_freq_time.loc[0, ["txn_time","unix_time", "is_fraud"]] = last_time, last_unix, False
trans_test_freq_time
Out[28]:
txn_time unix_time is_fraud
0 2023-09-20 09:14:00 1.695201e+09 False

В конфигах выставлена частота транзакций от 1 до 5 минут включительно

In [29]:
freq_values = []

for i in range(1,7):
    txn_time, txn_unix, freq = gen_time_for_frequent_trans(last_txn_unix=last_unix, configs=configs, test=True)
    freq_values.append(freq / 60)
        
    trans_test_freq_time.loc[i, "txn_time"] = txn_time
    trans_test_freq_time.loc[i, "unix_time"] = txn_unix
    trans_test_freq_time.loc[i, "is_fraud"] = True

    last_time = txn_time
    last_unix = txn_unix
    # к последней легальной транзакции присоединяем сгенерированные частые транзакции
    # trans_test_freq_time = pd.concat([trans_test_freq_time, trans_test_freq_time])

# средняя частота фрод транзакций - всех, кроме первой фрод транзакции
print("\n\n Mean freq: ",pd.Series(freq_values).mean(), " minutes\n\n")

# разница во времени с предыдущей транзакцией, в минутах
trans_test_freq_time["time_diff"] = trans_test_freq_time.unix_time.sub(trans_test_freq_time.unix_time.shift(1)) / 60
trans_test_freq_time

 Mean freq:  2.6666666666666665  minutes


Out[29]:
txn_time unix_time is_fraud time_diff
0 2023-09-20 09:14:00 1.695201e+09 False NaN
1 2023-09-20 09:17:00 1.695201e+09 True 3.0
2 2023-09-20 09:20:00 1.695202e+09 True 3.0
3 2023-09-20 09:21:00 1.695202e+09 True 1.0
4 2023-09-20 09:24:00 1.695202e+09 True 3.0
5 2023-09-20 09:26:00 1.695202e+09 True 2.0
6 2023-09-20 09:30:00 1.695202e+09 True 4.0


3. Функция derive_from_last_time¶

  • модуль data_generator.fraud.time. Ссылка на исходный код в Github
  • генерация времени через прибавление ко времени последней транзакции:
    • Либо на основании гео дистанции между транзакциями либо на основании заданного лага по времени.
    • Для генерации по дистанции надо передать geo_distance. Для генерации по лагу, НЕ передавать geo_distance, ввести lag_interval
  • Одна из целей использования функции это генерация времени фрод транзакций антифрод правило которых не является одним из правил с резкой сменой гео, чтобы они не попадали под такие правила

Основная логика функции
Use-case #1 - контроль времени, чтобы не попадать под антифрод правила резкой смены гео

  1. Берется время последней легальной транзакции и гео дистанция между этой транзакцией и текущей
  2. Берется порог скорости перемещения между совершением транзакций - из конфиг файла compr.yaml
  3. Считается разница во времени обеспечивающая допустимую скорость перемещение - значит непопадание под правило резкой смены гео
  4. Разница прибавляется ко времени последней легальной транзакции

Use-case #2 - создание времени на основании переданного лага по времени

  1. Берется время последней легальной транзакции
  2. Берется переданный желаемый лаг по времени
  3. Лаг прибавляется ко времени последней транзакции
  4. В данном случае гео дистанция не передается

Use-case #3 - создание времени на основании случайного лага по времени

  1. Берется время последней легальной транзакции
  2. random_lag=True
  3. Передаются мин. и макс. возможные значения лага
  4. Генерируется случайный лаг
  5. Лаг прибавляется ко времени последней транзакции
  6. В данном случае гео дистанция не передается

Демонстрация¶

In [10]:
from data_generator.fraud.time import derive_from_last_time

Расчет по гео

In [11]:
# Unix время последней транзакции
last_unix_deriv = pd_timestamp_to_unix(pd.to_datetime("2025-06-20 11:57:12", format="%Y-%m-%d %H:%M:%S"))
In [44]:
# Передаем дистанцию и порог скорости км/ч
geo_distance = 1800

_, derived_unix = derive_from_last_time(last_unix_deriv, geo_distance=geo_distance, threshold=800)
In [45]:
# Смотрим разницу во времени
pd.to_timedelta((derived_unix - last_unix_deriv), unit="s")
Out[45]:
Timedelta('0 days 05:31:17')
In [50]:
# Скорость перемещения км/ч. Должна получится ниже или равна порогу в 800. Т.к. делим на секунды то делим также на 3600

geo_distance / ((derived_unix - last_unix_deriv) / 3600)
Out[50]:
326.0049303214771


4. Функция get_time_fraud_txn¶

  • модуль data_generator.fraud.compr.time. Ссылка на исходный код в Github
  • конечная функция генерации времени для compomised фрода, использует в себе другие функции времени

Основная логика функции

  1. в зависимости от переданного антифрод правила выбирает функцию для генерации времени
  2. Для этого применяет показанные ранее функции
    • generate_time_fast_geo_jump
    • gen_time_for_frequent_trans
    • derive_from_last_time

Есть также вариант простого семплирования времени в соотвествии с одним из распределений времени заложенном в конфигах: Offline_24h_Fraud, Online_Fraud, Offline_Day_Fraud. Сейчас такой вариант будет применен если переданное антифрод правило под которое должна попасть транзакция не входит ни в одно правило упомянутое в if-elif блоке. Но на данный момент таких правил нет.




Генерация части данных транзакции, генерация суммы транзакции¶



1. Класс FraudTxnPartData - генерация части данных транзакции¶

  • модуль data_generator.fraud.compr.txndata. Ссылка на исходный код в Github
  • генерирует: мерчант id, координаты, ip адрес, город, device id, канал, тип транзакции.

Основная логика класса

  1. Отталкивается от антифрод правила под которое создается транзакция и онлайн статуса транзакции. Так, например, если транзакция оффлайн то для значений ip адреса, device id будут возвращены "not applicable", np.nan соотвественно, а при онлайн транзакции ip адрес и device id.
  2. Основной метод - get_data(). Возвращает упомянутые ранее данные или то, что должно быть вместо них в транзакции. Включает в себя другие методы, которые вызываются в зависимости от правила:
    • another_city() - имитация транзакции в городе отличном от города клиента. Для онлайн это: другой ip (и при этом другого города), другое устройство, координаты другого города. Для оффлайна: мерчант из другого города, координаты этого мерчанта.
    • new_device_and_ip() - чисто онлайн метод. Получение device id отличного от id имеющихся у клиента и ip адреса отличного от клиента. Может вернуть при этом либо ip другого города либо ip города клиента, но отличный от ip клиента.
    • freq_trans() - чисто онлайн метод. Сделан для правила trans_freq_increase - резкое учащение транз-ций. Использует внутри new_device_and_ip(), но только кэширует созданные данные в атрибут last_txn чтобы в следующих транзакциях внутри get_data() обращаться к кэшированным данным. Это для того, чтобы для одного фрод кейса trans_freq_increase не менялись данные о девайсе, ip и т.д.
  3. Для генерации данных нуждается в переданных данных о текущем клиенте в атрибут client_info в виде namedtuple. Подразумевается что при итерировании через клиентов при помощи itertuples() мы передаем namedtuple в этот атрибут

Демонстрация¶

In [51]:
from data_generator.fraud.compr.txndata import FraudTxnPartData
part_data = FraudTxnPartData(configs=configs)
In [53]:
# Класс должен получить данные о клиенте в виде namedtuple
for client_info in configs.clients.loc[[1]].itertuples():
    part_data.client_info = client_info
part_data.client_info
Out[53]:
Pandas(Index=1, client_id=418, city_id=28, birth_date=Timestamp('1991-10-07 00:00:00'), sex='male', region='Челябинская', city='Магнитогорск', timezone='UTC+5', lat=53.4071891, lon=58.9791432, population=408401, home_ip='2.60.1.142')
In [59]:
# Какие правила под compromised фрод есть
configs.rules
Out[59]:
rule weight online
0 fast_geo_change 0.12500 False
1 fast_geo_change_online 0.21875 True
2 new_ip_and_device_high_amount 0.25000 True
3 new_device_and_high_amount 0.18750 True
4 trans_freq_increase 0.21875 True
In [65]:
# Например возьмем правило быстрой смены гео. Транзакция оффлайн
rule = "fast_geo_change"

merchant_id, trans_lat, trans_lon, trans_ip, trans_city, device_id, channel, txn_type \
                            = part_data.get_data(rule=rule, online=False, category_name="gas_transport", txn_num=1)
In [66]:
# Город будет отличаться от города клиента. Также будут отличаться координаты, device_id
client_city = part_data.client_info.city

print(f"""Город клиента: {client_city}
Город транзакции: {trans_city}""")
Город клиента: Магнитогорск
Город транзакции: Липецк
In [68]:
# Например возьмем правило транзакции с другого ip (при этом ip другого города) и другого девайса
rule = "new_ip_and_device_high_amount"

merchant_id, trans_lat, trans_lon, trans_ip, trans_city, device_id, channel, txn_type \
                            = part_data.get_data(rule=rule, online=True, category_name="shopping_net", txn_num=1)
In [71]:
# Город будет отличаться от города клиента. Также будут отличаться координаты, ip адрес, device_id

print(f"""Город клиента: {client_city}
Город транзакции: {trans_city}""")
Город клиента: Магнитогорск
Город транзакции: Стерлитамак
In [74]:
# Нужно подгрузить девайсы клиентов и взять девайс(ы) клиента
clients_devices = pd.read_csv(data_paths["base"]["client_devices"])
client_id = part_data.client_info.client_id
devices = clients_devices.loc[clients_devices.client_id == client_id]
devices
Out[74]:
client_id platform device_id
397 418 iOS 703
5674 418 Windows 704
In [75]:
# девайс транзакции

print(f"""Device id транзакции: {device_id}""")
Device id транзакции: 12780


2. Класс TransAmount¶

  • модуль data_generator.fraud.compr.txndata. Ссылка на исходный код в Github
  • генерация суммы транзакции для compromised client фрода.
  • демонстрации работы не будет, только объяснение

Основная логика класса

  1. создает сумму по нормальному распределению с ограничениями
  2. Для всех правил кроме trans_freq_increase создает сумму на основе датафрейма из конфигов configs.fraud_amounts
  3. Для trans_freq_increase создает сумму на основе индивидуальных конфигов для этого правила берущихся из configs.rules_cfg["freq_txn"]
  4. В обоих случаях случайно применяет целочисленное округление через функцию amt_rounding из модуля data_generator.utils - либо округляет либо оставляет сумму как есть. В свою очередь целочисленное округление включает случайное число округления: 1, 10, 100, 1000, но не больше самой суммы.


3. Функция генерации одной транзакции gen_purchase_fraud_txn¶

  • модуль data_generator.fraud.compr.txns. Ссылка на исходный код в Github
  • полное создание одной транзакции

Основная логика

  1. На основе переданного правила, последней легальной транзакции клиента и других аргументов создает целую транзакцию
  2. Использует:
    • sample_category() - функция случайного выбора категории покупки
    • ранее упомянутый FraudTxnPartData - мерчант, гео, ip и др.
    • ранее упомянутый TransAmount - сумма транзакции
    • calc_distance() - функция расчета дистанции между текущей и последней легальной транзакцией
    • ранее упомянутая get_time_fraud_txn() - генерация времени
In [78]:
def gen_purchase_fraud_txn(rule, client_trans_df, configs: ComprClientFraudCfg, \
                           part_data: FraudTxnPartData, fraud_amts: TransAmount, \
                           txn_num=0, lag=False):
    """
    Генерация одной compromised client фрод транзакции для клиента.
    ------------------------------------------------
    rule - str.
    client_trans_df - датафрейм с транзакциями клиента.
    configs - ComprClientFraudCfg. Конфиги и данные для генерации фрод транзакций.
    client_device_ids - pd.Series. id девайсов клиента.
    part_data - FraudTxnPartData.
    fraud_amts - TransAmount class.
    txn_num - int. Какая по счету транзакция в данном фрод кейсе.
    lag - bool. Нужен ли лаг по времени от последней легальной транзакции.
          Используется для trans_freq_increase
    -------------------------------------------------
    Возвращает словарь с готовой транзакцией
    """
    client_info = part_data.client_info
    rules_cfg = configs.rules_cfg
    
    # Запись о последней транзакции клиента
    last_txn = client_trans_df.loc[client_trans_df.unix_time == client_trans_df.unix_time.max()]
    
    # Записываем данные клиента в переменные
    client_id = client_info.client_id

    # Берем значение online флага для выбранного правила
    online = configs.rules.loc[configs.rules.rule == rule, "online"].iat[0]
    
    # Семплирование категории. У категорий свой вес в разрезе вероятности быть фродом
    category = sample_category(configs.categories, online=online, is_fraud=is_fraud)
    
    category_name = category["category"].iat[0]
    round_clock = category["round_clock"].iat[0]
    
    # Генерация суммы транзакции. 
    # Пока что для всех правил кроме trans_freq_increase генерация через один и тот же метод
    if rule == "trans_freq_increase":
        amount = fraud_amts.freq_trans_amount()
    else:
        amount = fraud_amts.fraud_amount(category_name=category_name)
    
    partial_data = part_data.get_data(rule=rule, online=online, category_name=category_name, \
                                      txn_num=txn_num)
    # Распаковка кортежа в переменные
    merchant_id, trans_lat, trans_lon, trans_ip, trans_city, device_id, channel, txn_type = partial_data
    
    # Физическое расстояние между координатами последней транзакции и координатами текущей.
    geo_distance = calc_distance(lat_01=last_txn.trans_lat.iat[0], lon_01=last_txn.trans_lon.iat[0], \
                                 lat_02=trans_lat, lon_02=trans_lon)
    
    txn_time, txn_unix = get_time_fraud_txn(trans_df=client_trans_df, configs=configs, online=online, \
                                            round_clock=round_clock, rule=rule, geo_distance=geo_distance, \
                                            lag=lag)
    # Только для freq_trans статус может отличаться от declined и is_fraud быть False для части транз-ций
    # При кол-ве до freq_min - approved и False. Условно, детект по этому правилу начинается
    # с freq_min транз-ций
    freq_min = rules_cfg["freq_txn"]["txn_num"]["min"]
    if rule == "trans_freq_increase" and (txn_num > 0 and txn_num < freq_min):
        rule_to_txn = "not applicable"
        status = "approved"
        is_fraud = False

    elif rule == "trans_freq_increase":
        rule_to_txn = "trans_freq_increase"
        status = "declined"
        is_fraud = True

    else:
        rule_to_txn = rule
        status = "declined"
        is_fraud = True
        
    # Статичные значения для данной функции
    is_suspicious = False
    account = np.nan
    
    # Возвращаем словарь со всеми данными сгенерированной транзакции
    return build_transaction(client_id=client_id, txn_time=txn_time, txn_unix=txn_unix, amount=amount, \
                             txn_type=txn_type,  channel=channel, category_name=category_name, online=online, \
                             merchant_id=merchant_id, trans_city=trans_city, trans_lat=trans_lat, \
                             trans_lon=trans_lon, trans_ip=trans_ip, device_id=device_id, account=account, \
                             is_fraud=is_fraud, is_suspicious=is_suspicious, status=status, rule=rule_to_txn)

Демонстрация¶

In [28]:
from data_generator.fraud.compr.txndata import FraudTxnPartData, TransAmount
from data_generator.fraud.compr.txns import gen_purchase_fraud_txn
from data_generator.utils import create_txns_df, calc_distance

transactions = create_txns_df(base_cfg["txns_df"])
part_data = FraudTxnPartData(configs)
txn_amt = TransAmount(configs)

for client in configs.clients.loc[[1]].itertuples():
    client_info = client
client_id = client_info.client_id

client_txns_df = configs.transactions.query("client_id == @client_id")
part_data.client_info = client_info
client_info
Out[28]:
Pandas(Index=1, client_id=1125, city_id=9, birth_date=Timestamp('1959-03-24 00:00:00'), sex='female', region='Кемеровская', city='Новокузнецк', timezone='UTC+7', lat=53.7942757, lon=87.2144046, population=547885, home_ip='2.60.4.47')
In [29]:
configs.rules
Out[29]:
rule weight online
0 fast_geo_change 0.12500 False
1 fast_geo_change_online 0.21875 True
2 new_ip_and_device_high_amount 0.25000 True
3 new_device_and_high_amount 0.18750 True
4 trans_freq_increase 0.21875 True

В примере возьмем не просто последнюю транзакцию клиента, а последнюю онлайн. Конечно при генерации будет учитываться именно последняя транзакция любого типа, но тут возьмем, чтобы увидеть в т.ч. разные ip адреса и device id

In [30]:
# Возьмем последнюю легальную ОНЛАЙН транзакцию клиента. Этого достаточно
client_one_txn =  client_txns_df.query("online == True").loc[[client_txns_df.query("online == True").unix_time.idxmax()]]

# Генерация одной фрод транзакции под антифрод правило быстрой смены гео при онлайн транзакции
fraud_one_test = gen_purchase_fraud_txn(rule="fast_geo_change_online", client_trans_df=client_one_txn, \
                                        configs=configs, part_data=part_data, fraud_amts=txn_amt,
                                        txn_num=1, lag=False)

fraud_all_txns = pd.concat([client_one_txn, pd.DataFrame([fraud_one_test])]).reset_index(drop=True)
fraud_all_txns
Out[30]:
client_id txn_time unix_time amount type channel category online merchant_id trans_city trans_lat trans_lon trans_ip device_id account is_fraud is_suspicious status rule
0 1125 2025-01-12 10:16:00 1736676960 1.0 purchase ecom misc_net True 6930.0 Новокузнецк 53.794276 87.214405 2.60.4.47 1961.0 NaN False False approved not applicable
1 1125 2025-01-12 11:50:52 1736682652 5840.0 purchase ecom misc_net True 6959.0 Уфа 54.734853 55.957865 5.8.14.16 14984.0 NaN True False declined fast_geo_change_online

Выше обратите внимание на разные города, ip адреса и device id. Также на status и rule транзакции


Расчет разницы во времени между последней легальной транз. и фрод транз.

In [31]:
# Расчет разницы во времени между последней легальной транз. и фрод транз.
pd.to_timedelta(fraud_all_txns.unix_time.sub(fraud_all_txns.unix_time.shift(1)).abs(), unit="s")
Out[31]:
0               NaT
1   0 days 01:34:52
Name: unix_time, dtype: timedelta64[ns]

Расчет расстояния между координатами транзакций. Будет видно, что для разницы во времени дистанция довольно большая

In [32]:
lat_prev = fraud_all_txns.loc[0, "trans_lat"]
lon_prev = fraud_all_txns.loc[0, "trans_lon"]
lat_now = fraud_all_txns.loc[1, "trans_lat"]
lon_now = fraud_all_txns.loc[1, "trans_lon"]
In [33]:
calc_distance(lat_01=lat_prev, lon_01=lon_prev, lat_02=lat_now, lon_02=lon_now)
Out[33]:
2022.44


4. Функция обертка trans_freq_wrapper для функции gen_purchase_fraud_txn¶

  • модуль data_generator.fraud.compr.txns. Ссылка на исходный код в Github
  • обертка нужна под правило trans_freq_increase
  • т.к. правило trans_freq_increase подразумевает фрод кейс с несколькими транзакциями, то gen_purchase_fraud_txn должна быть вызвана несколько раз. Эта функция обеспечивает это и контроль логики для фрод кейса под это правило. Это единственное правило из compromised clients правил где создается больше одной транзакции

Основная логика функции

  1. Задача функции вызвать gen_purchase_fraud_txn указанное число раз и записать это все во временный датафрейм и вернуть его как результат
  2. Также задача выставить значение аргумента lag для gen_purchase_fraud_txn в зависимости от того первая это транзакция в серии или не первая. lag значит нужен ли лаг по времени от предыдущей транзакции, подразумевается что он нужен для первой фрод транзакции, чтобы была достаточная временная разница с последней легальной транзакцией, чтобы не попадать под правило резкой смены гео.

Демонстрация¶

In [99]:
from data_generator.fraud.compr.txns import trans_freq_wrapper

transactions = create_txns_df(base_cfg["txns_df"])

part_data = FraudTxnPartData(configs)
txn_amt = TransAmount(configs)

for client in configs.clients.loc[[1]].itertuples():
    client_info = client
client_id = client_info.client_id

client_txns_df = configs.transactions.query("client_id == @client_id")
part_data.client_info = client_info
client_info
Out[99]:
Pandas(Index=1, client_id=1971, city_id=3, birth_date=Timestamp('1994-03-08 00:00:00'), sex='female', region='Удмуртская', city='Ижевск', timezone='UTC+4', lat=56.8527444, lon=53.2113961, population=628117, home_ip='2.60.7.69')
In [102]:
# Датафрейм с последней легальной транзакцией клиента
client_txns_copy = client_txns_df.loc[[client_txns_df.unix_time.idxmax()]].copy()

# txns_total - сколько транзакций будет в серии
fraud_only = trans_freq_wrapper(client_txns_temp=client_txns_copy, txns_total=6, configs=configs, \
                                part_data=part_data, fraud_amts=txn_amt)

client_trans_copy = pd.concat([client_txns_copy, fraud_only], ignore_index=True)

Результат

  • первая в списке транзакция это легальная транзакция клиента, остальное все фрод в рамках правила trans_freq_increase
  • обратите внимание что условный фрод детект происходит не сразу, и транзакция помечается как фрод, только на 4-й раз. Этот порог задается в конфиге compr.yaml. Т.е. как-будто бы 3 частых транзакции еще нормально, но 4 и более - фрод.
In [4]:
client_txns_copy
Out[4]:
client_id txn_time unix_time amount type channel category online merchant_id trans_city trans_lat trans_lon trans_ip device_id account is_fraud is_suspicious status rule
0 445 2025-01-30 12:41:39 1738240899 3000.00 purchase ecom misc_net True 6960.0 Москва 55.753879 37.620373 2.60.1.169 782.0 NaN False False approved not applicable
1 445 2025-01-30 15:59:57 1738252797 3000.00 purchase ecom shopping_net True 6947.0 Кострома 57.802945 40.990728 5.8.8.149 11218.0 NaN True False approved not applicable
2 445 2025-01-30 16:00:57 1738252857 4817.66 purchase ecom shopping_net True 6947.0 Кострома 57.802945 40.990728 5.8.8.149 11218.0 NaN True False approved not applicable
3 445 2025-01-30 16:03:57 1738253037 2892.04 purchase ecom shopping_net True 6947.0 Кострома 57.802945 40.990728 5.8.8.149 11218.0 NaN True False approved not applicable
4 445 2025-01-30 16:04:57 1738253097 5200.00 purchase ecom misc_net True 6947.0 Кострома 57.802945 40.990728 5.8.8.149 11218.0 NaN True False declined trans_freq_increase
5 445 2025-01-30 16:07:57 1738253277 3670.88 purchase ecom misc_net True 6947.0 Кострома 57.802945 40.990728 5.8.8.149 11218.0 NaN True False declined trans_freq_increase
6 445 2025-01-30 16:10:57 1738253457 4520.00 purchase ecom shopping_net True 6947.0 Кострома 57.802945 40.990728 5.8.8.149 11218.0 NaN True False declined trans_freq_increase

Разница во времени с предыдущей транзакцией
Можно заметить что сперва большая разница между первой фрод транзакцией и последней легальной(т.е. которая самая первая), а дальше идут разницы меньше 5 минут, так и задумано.

In [103]:
pd.to_timedelta(client_trans_copy.unix_time.sub(client_trans_copy.unix_time.shift(1)).abs(), unit="s")
Out[103]:
0               NaT
1   0 days 02:44:32
2   0 days 00:01:00
3   0 days 00:03:00
4   0 days 00:02:00
5   0 days 00:02:00
6   0 days 00:05:00
Name: unix_time, dtype: timedelta64[ns]

Проверим что дистанция между координатами последней легальной и первой фрод транзакциями приемлема с точки зрения разницы времени

In [104]:
lat_prev = client_trans_copy.loc[0, "trans_lat"]
lon_prev = client_trans_copy.loc[0, "trans_lon"]
lat_now = client_trans_copy.loc[1, "trans_lat"]
lon_now = client_trans_copy.loc[1, "trans_lon"]
In [105]:
calc_distance(lat_01=lat_prev, lon_01=lon_prev, lat_02=lat_now, lon_02=lon_now)
Out[105]:
293.43




Генерация нескольких транзакций, запись транзакций в файл¶



1. Класс FraudTxnsRecorder¶

  • модуль data_generator.fraud.recorder. Ссылка на исходный код в Github
  • Запись фрод транзакций в файл. Этот класс таже применяется для записи транзакций при дроп фроде, о котором будет в следующих ноутбуках

Основная логика

  1. Получает в атрибут all_txns pd.DataFrame со всеми созданными транзакции по определенному типу фрода
  2. Записывает этот датафрейм в parquet в двух директориях: индивидуальной директории текущей генерации и директории последнего запуска генератора транзакций. Т.е. например data/generated/history/<текущий_запуск>/<тип_фрода> и data/generated/latest/
  3. В случае compromised фрода подразумевается встраивание объекта этого класса в функцию gen_multi_fraud_txns




2. Функция генерации нескольких фрод транзакций gen_multi_fraud_txns¶

  • модуль data_generator.fraud.compr.txns. Ссылка на исходный код в Github
  • полная генерация множетсва транзакций для переданных клиентов под разные антифрод правила в рамках compromised client фрода

Основная логика

  1. Итерирование через переданных клиентов и генерация фрод транзакций для них.
  2. Антифрод правило для каждого клиента берется случайно и под это правило генерируется фрод для клиента.
  3. Все датафреймы с фрод транзакциями пишутся в общий список объявенный перед началом цикла. Потом всё соединяется через pd.concat и передается в FraudTxnsRecorder.all_txns, затем вызвается FraudTxnsRecorder.write_to_file() и транзакции записываются в файлы в двух директориях.
In [439]:
def gen_multi_fraud_txns(configs: ComprClientFraudCfg, part_data: FraudTxnPartData, \
                         fraud_amts: TransAmount, txn_recorder: FraudTxnsRecorder):
    """
    clients_subset: pd.DataFrame. Клиенты у которых будут фрод транзакции. Сабсет клиентов для кого нагенерили
                     легальных транзакций ранее.
    configs: ComprClientFraudCfg. Конфиги для транзакций.
    part_data: FraudTxnPartData. Генератор части данных транзакций.
    fraud_amts: TransAmount. Генератор сумм транзакций.
    txn_recorder: FraudTxnsRecorder. 
    """
    all_fraud_txns = []
    # Конфиги кол-ва транз. для правила trans_freq_increase
    freq_cfg = configs.rules_cfg["freq_txn"]["txn_num"]

    for client in configs.clients.itertuples():
        rule = sample_rule(configs.rules)

        client_txns = configs.transactions.loc[configs.transactions.client_id == client.client_id]
        # Записываем данные текущего клиента в атрибут client_info класса FraudTxnPartData
        part_data.client_info = client
        
        # Это правило отдельно т.к. такой случай имеет несколько транз-ций
        if rule == "trans_freq_increase":
            client_txns_temp = client_txns.loc[[client_txns.unix_time.idxmax()]]
            # Сколько транз. будет создано под это правило
            low = freq_cfg["min"]
            high = freq_cfg["max"]
            txns_total = np.random.randint(low, high + 1) 

            # Генерируем txns_total число фрод транзакций. Датафрейм с ними записываем в переменную
            fraud_only = trans_freq_wrapper(client_txns_temp=client_txns_temp, \
                                            txns_total=txns_total, configs=configs, \
                                            part_data=part_data, fraud_amts=fraud_amts)
            
            # Добавляем созданные транзакции в общий список и сразу переводим цикл на следующую итерацию
            all_fraud_txns.append(fraud_only)
            continue

        # Остальные правила. Генерация одной транз-ции
        else:
            one_txn = gen_purchase_fraud_txn(rule=rule, client_trans_df=client_txns, \
                                             configs=configs, part_data=part_data, \
                                             fraud_amts=fraud_amts)
            
            all_fraud_txns.append(pd.DataFrame([one_txn]))

    # Запись транзакций в файл  
    txn_recorder.all_txns = pd.concat(all_fraud_txns, ignore_index=True)
    txn_recorder.write_to_file()

Демонстрация¶

In [10]:
from data_generator.fraud.compr.txns import gen_multi_fraud_txns
from data_generator.fraud.recorder import FraudTxnsRecorder
from data_generator.fraud.compr.txndata import FraudTxnPartData, TransAmount

part_data = FraudTxnPartData(configs)
txn_amt = TransAmount(configs)
txn_recorder = FraudTxnsRecorder(configs)
In [11]:
# Тест
gen_multi_fraud_txns(configs=configs, part_data=part_data, fraud_amts=txn_amt, txn_recorder=txn_recorder)
In [12]:
data_storage = compr_cfg["data_storage"]
compr_subdir = data_storage["folder_name"] # Название поддиректории в папке созданной под текущую генерацию
compr_file = data_storage["files"]["txns"] # Название файла с транзакциями
path_to_compr = os.path.join(run_dir, compr_subdir, compr_file)

compr_fraud_demo = pd.read_parquet(path_to_compr)
In [13]:
compr_fraud_demo.head(5)
Out[13]:
client_id txn_time unix_time amount type channel category online merchant_id trans_city trans_lat trans_lon trans_ip device_id account is_fraud is_suspicious status rule
0 1114 2025-01-20 11:13:47 1737371627 24741.85 purchase ecom shopping_net True 6949.0 Иваново 56.999468 40.972823 5.8.23.242 12408.0 NaN True False declined new_ip_and_device_high_amount
1 1125 2025-01-18 18:47:28 1737226048 19148.95 purchase ecom misc_net True 6835.0 Новокузнецк 53.794276 87.214405 5.8.0.153 14458.0 NaN True False declined new_device_and_high_amount
2 2401 2025-01-20 10:57:21 1737370641 49142.25 purchase ecom shopping_net True 6964.0 Новосибирск 55.028102 82.921058 5.8.14.8 10034.0 NaN True False declined fast_geo_change_online
3 875 2025-01-20 10:00:45 1737367245 5400.00 purchase ecom shopping_net True 6812.0 Иркутск 52.286351 104.280655 5.8.12.79 14763.0 NaN True False declined new_ip_and_device_high_amount
4 3522 2025-01-20 00:47:50 1737334070 8570.35 purchase ecom misc_net True 6895.0 Ярославль 57.621614 39.897878 5.8.28.44 12616.0 NaN True False declined new_ip_and_device_high_amount
In [14]:
compr_fraud_demo.shape
Out[14]:
(185, 19)

Возьмем пример для каждого правила: последняя легальная транзакция клиента, затем фрод, который у него был

In [15]:
# Подгрузим легальные транзакции. Сразу отсортируем по client_id и времени

legit_txns_full = pd.read_parquet(run_dir + "/legit/legit_txns.parquet").sort_values(["client_id","unix_time"])
legit_txns_full.head(2)
Out[15]:
client_id txn_time unix_time amount type channel category online merchant_id trans_city trans_lat trans_lon trans_ip device_id account is_fraud is_suspicious status rule
1108 4 2025-01-02 14:17:00 1735827420 1722.00 purchase POS grocery_pos False 4336.0 Ростов-на-Дону 47.186882 39.540858 not applicable NaN NaN False False approved not applicable
1837 4 2025-01-03 08:14:00 1735892040 1070.83 purchase POS shopping_pos False 6038.0 Ростов-на-Дону 47.269532 39.734244 not applicable NaN NaN False False approved not applicable
In [16]:
# Возьмем только последнюю легальную транзакцию для каждого клиента
legit_full_last_only = legit_txns_full.groupby("client_id", as_index=False).tail(1)
legit_full_last_only.head(3)
Out[16]:
client_id txn_time unix_time amount type channel category online merchant_id trans_city trans_lat trans_lon trans_ip device_id account is_fraud is_suspicious status rule
18764 4 2025-01-19 21:53:00 1737323580 1837.07 purchase POS grocery_pos False 948.0 Ростов-на-Дону 47.264105 39.643790 not applicable NaN NaN False False approved not applicable
19043 5 2025-01-20 08:48:00 1737362880 1.00 purchase POS shopping_pos False 2650.0 Ростов-на-Дону 47.198945 39.493719 not applicable NaN NaN False False approved not applicable
17964 17 2025-01-19 18:24:20 1737311060 473.47 purchase POS home False 6204.0 Тюмень 57.211488 65.566663 not applicable NaN NaN False False approved not applicable
In [17]:
# Отфильтруем только те легальные, которые принадлежат клиентам у которых был фрод

fraud_client_ids = compr_fraud_demo.client_id.unique()
legit_txns = legit_full_last_only.loc[legit_full_last_only.client_id.isin(fraud_client_ids)]
legit_txns.head(2)
Out[17]:
client_id txn_time unix_time amount type channel category online merchant_id trans_city trans_lat trans_lon trans_ip device_id account is_fraud is_suspicious status rule
18666 66 2025-01-19 21:34:06 1737322446 1.0 purchase POS shopping_pos False 2549.0 Москва 55.702551 37.417362 not applicable NaN NaN False False approved not applicable
19088 97 2025-01-20 09:04:00 1737363840 1000.0 purchase POS gas_transport False 3188.0 Орёл 52.934794 36.058780 not applicable NaN NaN False False approved not applicable
In [18]:
# Соединим последние легальные и созданный фрод.

last_leg_and_fraud = pd.concat([legit_txns, compr_fraud_demo]).sort_values(["client_id","unix_time"]).reset_index(drop=True)
last_leg_and_fraud.head(2)
Out[18]:
client_id txn_time unix_time amount type channel category online merchant_id trans_city trans_lat trans_lon trans_ip device_id account is_fraud is_suspicious status rule
0 66 2025-01-19 21:34:06 1737322446 1.0 purchase POS shopping_pos False 2549.0 Москва 55.702551 37.417362 not applicable NaN NaN False False approved not applicable
1 66 2025-01-19 21:42:01 1737322921 7000.0 purchase ecom shopping_net True 6923.0 Москва 55.753879 37.620373 5.8.30.49 10821.0 NaN True False declined new_device_and_high_amount

Правило fast_geo_change

  • резкая смена гео между транзакциями.
  • фрод транзакция оффлайн
In [19]:
# Чтобы показать не только фрод но и последнюю легальную транзакцию, нужно фильтровать по client_id
# И взять client_id клиента у которого был нужный фрод
fast_geo_client = last_leg_and_fraud.query("rule == 'fast_geo_change'").client_id.head(1).iat[0]

last_leg_and_fraud.loc[last_leg_and_fraud.client_id == fast_geo_client]
Out[19]:
client_id txn_time unix_time amount type channel category online merchant_id trans_city trans_lat trans_lon trans_ip device_id account is_fraud is_suspicious status rule
15 527 2025-01-20 12:09:00 1737374940 3627.31 purchase POS grocery_pos False 3019.0 Иваново 56.994509 40.883388 not applicable NaN NaN False False approved not applicable
16 527 2025-01-20 12:25:34 1737375934 32204.00 purchase POS misc_pos False 505.0 Тверь 56.826437 35.920547 not applicable NaN NaN True False declined fast_geo_change

Правило fast_geo_change_online

  • резкая смена гео между транзакциями.
  • фрод транзакция онлайн
In [20]:
fast_geo_net_client = last_leg_and_fraud.query("rule == 'fast_geo_change_online'").client_id.head(1).iat[0]

last_leg_and_fraud.loc[last_leg_and_fraud.client_id == fast_geo_net_client]
Out[20]:
client_id txn_time unix_time amount type channel category online merchant_id trans_city trans_lat trans_lon trans_ip device_id account is_fraud is_suspicious status rule
2 97 2025-01-20 09:04:00 1737363840 1000.0 purchase POS gas_transport False 3188.0 Орёл 52.934794 36.058780 not applicable NaN NaN False False approved not applicable
3 97 2025-01-20 09:06:35 1737363995 3700.0 purchase ecom misc_net True 6878.0 Брянск 53.242007 34.365272 5.8.3.245 11543.0 NaN True False declined fast_geo_change_online

Правило new_ip_and_device_high_amount

  • транзакция на большую сумму с другого ip + это ip другого города, но без гео скачка; а также с другого устройства.
  • фрод транзакция онлайн
In [21]:
new_dev_and_ip_client = last_leg_and_fraud.query("rule == 'new_ip_and_device_high_amount'").client_id.head(1).iat[0]

last_leg_and_fraud.loc[last_leg_and_fraud.client_id == new_dev_and_ip_client]
Out[21]:
client_id txn_time unix_time amount type channel category online merchant_id trans_city trans_lat trans_lon trans_ip device_id account is_fraud is_suspicious status rule
4 398 2025-01-20 12:58:00 1737377880 742.4 purchase POS personal_care False 5583.0 Тверь 56.882587 35.841957 not applicable NaN NaN False False approved not applicable
5 398 2025-01-20 17:50:22 1737395422 4000.0 purchase ecom misc_net True 6937.0 Новосибирск 55.028102 82.921058 5.8.19.222 11861.0 NaN True False declined new_ip_and_device_high_amount

Правило new_device_and_high_amount

  • транзакция на большую сумму с другого ip, но это ip города клиента; а также с другого устройства.
  • фрод транзакция онлайн
In [22]:
new_dev_client = last_leg_and_fraud.query("rule == 'new_device_and_high_amount'").client_id.head(1).iat[0]

last_leg_and_fraud.loc[last_leg_and_fraud.client_id == new_dev_client]
Out[22]:
client_id txn_time unix_time amount type channel category online merchant_id trans_city trans_lat trans_lon trans_ip device_id account is_fraud is_suspicious status rule
0 66 2025-01-19 21:34:06 1737322446 1.0 purchase POS shopping_pos False 2549.0 Москва 55.702551 37.417362 not applicable NaN NaN False False approved not applicable
1 66 2025-01-19 21:42:01 1737322921 7000.0 purchase ecom shopping_net True 6923.0 Москва 55.753879 37.620373 5.8.30.49 10821.0 NaN True False declined new_device_and_high_amount

Правило trans_freq_increase

  • резкое учащение транзакций клиента. Несколько частых транзакций подряд
  • фрод транзакции онлайн
  • первые несколько транзакций из серии не отмечены как фрод и не отклонены, но подразумевается, что это тоже фрод, просто на тот момент еще не был достигнут порог частых транзакций. Напоминаю, что первая транзакция это последняя легальная транзакция клиента
  • суммы в этом типе фрода не слишком большие, подразумевается будто мошенник делает частые транзакции, но суммы не особо большие, чтобы избежать детекта
In [23]:
freq_txns_client = last_leg_and_fraud.query("rule == 'trans_freq_increase'").client_id.head(1).iat[0]

last_leg_and_fraud.loc[last_leg_and_fraud.client_id == freq_txns_client]
Out[23]:
client_id txn_time unix_time amount type channel category online merchant_id trans_city trans_lat trans_lon trans_ip device_id account is_fraud is_suspicious status rule
6 444 2025-01-19 11:08:00 1737284880 1030.15 purchase POS home False 4250.0 Санкт-Петербург 60.029397 30.307338 not applicable NaN NaN False False approved not applicable
7 444 2025-01-20 03:54:52 1737345292 2555.48 purchase ecom shopping_net True 6909.0 Севастополь 44.616733 33.525355 5.8.3.179 11052.0 NaN False False approved not applicable
8 444 2025-01-20 03:55:52 1737345352 4500.00 purchase ecom shopping_net True 6909.0 Севастополь 44.616733 33.525355 5.8.3.179 11052.0 NaN False False approved not applicable
9 444 2025-01-20 03:57:52 1737345472 2186.00 purchase ecom grocery_net True 6909.0 Севастополь 44.616733 33.525355 5.8.3.179 11052.0 NaN False False approved not applicable
10 444 2025-01-20 04:02:52 1737345772 2200.00 purchase ecom shopping_net True 6909.0 Севастополь 44.616733 33.525355 5.8.3.179 11052.0 NaN True False declined trans_freq_increase
11 444 2025-01-20 04:03:52 1737345832 3914.00 purchase ecom grocery_net True 6909.0 Севастополь 44.616733 33.525355 5.8.3.179 11052.0 NaN True False declined trans_freq_increase
12 444 2025-01-20 04:08:52 1737346132 4000.00 purchase ecom misc_net True 6909.0 Севастополь 44.616733 33.525355 5.8.3.179 11052.0 NaN True False declined trans_freq_increase




Оркестрация генерации compromised фрод транзакций¶


1. Класс ComprRunner¶

  • модуль data_generator.runner.compr. Ссылка на исходный код в Github
  • оркестрация генерации compromised client fraud транзакций
  • это конечный уровень для compromised транзакций. Метод run() этого класса вызывается в файле запуска генератора всех транзакций run_generator.py
In [26]:
class ComprRunner:
    """
    Запуск генерации транзакций compromised фрода.
    ---------
    Атрибуты:
    ---------
    cfg_builder: ComprConfigBuilder.
    configs: ComprClientFraudCfg. Конфиги и данные для генерации транзакций.
    part_data: FraudTxnPartData. Генерация части данных транзакции:
               мерчант, геопозиция, город, IP адрес и др.
    fraud_amts: TransAmount. Генерация суммы транзакций.
    txn_recorder: FraudTxnsRecorder. Запись транзакций в файл.
    text: str. Текст для вставки в спиннер.
    """
    def __init__(self, base_cfg, legit_cfg, time_cfg, fraud_cfg, compr_cfg, run_dir):
        """
        base_cfg: dict. Конфиги из base.yaml
        legit_cfg: dict. Конфиги из legit.yaml
        time_cfg: dict. Конфиги из time.yaml
        fraud_cfg: dict. Общие конфиги фрода из fraud.yaml
        compr_cfg: dict. Конфиги для compromised фрода из compr.yaml
        run_dir: str. Название директории для хранения сгенерированных
                 данных текущей генерации.
        """
        self.cfg_builder = ComprConfigBuilder(base_cfg=base_cfg, legit_cfg=legit_cfg, \
                                              time_cfg=time_cfg, fraud_cfg=fraud_cfg, \
                                              compr_cfg=compr_cfg, run_dir=run_dir)
        self.configs = self.cfg_builder.build_cfg()
        self.part_data = FraudTxnPartData(configs=self.configs)
        self.fraud_amts = TransAmount(configs=self.configs)
        self.txn_recorder = FraudTxnsRecorder(configs=self.configs)
        self.text = "Compromised clients fraud txns generation"


    @spinner_decorator
    def run(self):
        """
        Запуск генератора.
        """
        configs = self.configs
        part_data = self.part_data
        fraud_amts = self.fraud_amts
        txn_recorder = self.txn_recorder

        gen_multi_fraud_txns(configs=configs, part_data=part_data, fraud_amts=fraud_amts, \
                             txn_recorder=txn_recorder)