Bom dia

Há alguns anos, nossa equipe (conformidade em um banco suíço) enfrentou uma tarefa muito interessante: era necessário gerar um grande gráfico de transações entre clientes, empresas e caixas eletrônicos, adicionar padrões semelhantes aos de lavagem de dinheiro e outras atividades criminais a este gráfico e também adicionar um mínimo informações sobre os nós deste gráfico - nomes, endereços, horário etc. Obviamente, todos os dados tiveram que ser gerados do zero, sem usar os dados existentes do cliente.
Para resolver esse problema, um gerador foi escrito, que eu gostaria de compartilhar com você. Abaixo do recorte, você encontrará uma história explicando por que precisamos dela e uma descrição da operação do gerador. Para impaciente - aqui está o código . Eu ficaria feliz se alguém se beneficiaria com a nossa experiência.
Por que estamos fazendo tanta bobagem?
Nossa equipe decidiu participar como patrocinadores do hackathon LauzHack
. Uma das condições para participação no formato do patrocinador era o fornecimento de uma tarefa comercial real para os participantes. Naquele momento, tínhamos um projeto muito interessante relacionado à automação da busca por crimes financeiros e lavagem de dinheiro entre as transações de nossos clientes e, sem hesitar, decidimos oferecer a mesma tarefa aos participantes do hackathon.
Por razões óbvias, não podíamos usar dados reais, portanto tivemos que criá-los. Para tornar a tarefa o mais próxima possível da realidade, examinamos as estatísticas de dados reais e tentamos, como pudemos, aproximar os dados gerados das distribuições reais e também não poupamos a quantidade e a complexidade dos dados - não precisávamos de uma solução trabalhando em um gráfico de 100 nós e 200 conexões, estávamos procurando uma solução capaz de processar gráficos do tamanho de milhões de nós e bilhões de conexões e levando em consideração todas as informações disponíveis sobre nós e conexões.
O que conseguimos
E nós temos um gerador bastante rápido (ajustado pela quantidade de dados), interessante e configurável! Vamos entender em detalhes
Tipos de dados
Queremos ter um gráfico de transações financeiras, respectivamente, possíveis participantes deste gráfico são:
- Cliente - você pode dizer uma conta de um cliente abstrato de um banco. É descrito por nome, email, idade, trabalho, opiniões políticas, nacionalidade, educação e endereço de residência.
- Uma empresa é uma entidade comercial no sistema financeiro. É determinado pelo tipo de empresa, nome e país.
- ATM - grosso modo, os pontos de saída de dinheiro do gráfico controlado por nós. Definido por coordenadas geográficas.
- Transação - O fato de transferir dinheiro de um nó do gráfico para outro. Definido pelo nó inicial e final, quantidade, moeda e hora.
Para criar esses dados, usamos o Mimesis , uma ótima biblioteca para criar dados falsos.
Criando um gráfico: entidades básicas
Primeiro, você precisa criar todas as entidades básicas - clientes, empresas e caixas eletrônicos. O script leva o número de clientes que você deseja criar e, com base nisso, calcula o número de empresas e caixas eletrônicos. De acordo com nossos dados, o número de empresas que realizam um grande número de transações com clientes é de aproximadamente 2,5% do número de clientes e o número de caixas eletrônicos é de 0,05% do número de clientes. Esses valores são muito generalizados e não configuráveis (conectados no código do gerador).
Todas as informações são salvas em arquivos .csv. A gravação nesses arquivos ocorre em lotes, k linhas por vez. Este valor é configurado pelos argumentos do script. Além disso, três tipos de nós são gerados em paralelo.
Criando um gráfico: conexões entre entidades
Depois de criar as entidades básicas, começamos a conectá-las. Nesse estágio, ainda não estamos gerando as próprias transações, mas simplesmente o fato de que há uma conexão entre os nós. Isso foi feito para acelerar o processo de geração de todo o gráfico e funciona aproximadamente da seguinte maneira: se dois nós estiverem conectados, geramos um certo número de transações entre eles, espalhados no tempo. Se não estiver conectado, mas as transações entre esses nós não existirão.
A probabilidade de uma conexão entre os dois nós é configurada por meio de argumentos; os valores padrão estão listados abaixo.
Possíveis tipos de conexão:
- Cliente -> Cliente (p = 0,4%)
- Cliente -> Empresa (p = 1%)
- Cliente -> ATM (p = 3%)
- Empresa -> Cliente (p = 0,5%)
Como nós, todos os tipos de conexões são gerados em paralelo e gravados em seus arquivos em lotes.
Criação de gráfico: transações
Tendo os nós do gráfico e as conexões entre eles caindo na distribuição desejada, podemos começar a gerar transações. O processo é bastante simples em si, mas paralelizar é bastante difícil. Portanto, nesta fase, existem apenas dois fluxos independentes - transações originárias do cliente e transações originárias da empresa.
Nada de particularmente interessante acontece nesta fase: o script percorre a lista de conexões e gera um número aleatório de transações para cada conexão. Está escrito da mesma maneira - em arquivos .csv por pacotes.
Count Creations: Patterns
E aqui há pontos interessantes. Os tipos de padrões de comportamento que queríamos obter na coluna final:
- Fluxo - uma grande quantidade passa de um nó para outro, cada um desses nós transfere dinheiro para o próximo nível de nós e assim por diante, até o último nível enviar todo o dinheiro para um destinatário.
- Circular - a quantidade de dinheiro entra em um círculo e retorna à fonte.
- Tempo - uma certa quantia de dinheiro passa de um nó para outro com alguma frequência fixa.
Vamos examinar cada um desses padrões com mais detalhes:
Flow
Para começar, o número de níveis pelos quais o dinheiro precisará passar é selecionado. Em nossa implementação, esse número aleatório entre 2 e 6 não é configurável e está conectado ao código. Em seguida, dois nós do gráfico são selecionados - o remetente e o destinatário. Também é selecionada uma quantia aleatória, que o remetente enviará ao destinatário (de acordo com a fórmula inteligente 50000 * random() + 50000 * random()
).
Cada membro desta rede cobra algum tipo de taxa por seus serviços. Em nossa implementação, o preço máximo para a transferência de dinheiro pela rede será de 10% do valor transferido pelo remetente.
As transações geradas têm um turno no tempo das transações relativas do nível de rede anterior - ou seja, o dinheiro chega primeiro ao nível n-1 e só então passa ao nível n. Atrasos são selecionados aleatoriamente dentro de 4-5 dias. Além disso, as transações geradas possuem valores pseudo-aleatórios (limitados pelo valor inicial e levando em consideração as taxas de cada nó)
Circular
Ele é gerado de acordo com um princípio semelhante ao Flow, mas, em vez de diferentes remetentes e receptores e vários níveis nesse padrão, o dinheiro entra em círculo e retorna ao nó original. Todos os nós intermediários cobram uma taxa, como é o caso do Flow, e as transações também têm um deslocamento de tempo.
Tempo
O padrão mais simples. Uma certa quantia é enviada do remetente ao destinatário um número aleatório de vezes (de 5 a 50, não configurável) com mudanças de tempo pseudo-aleatórias.
Todas as novas transações são gravadas da mesma maneira em arquivos .csv em lotes.
Randomização gráfica e coleta de todas as transações em um arquivo
Nesta fase, temos vários arquivos .csv:
- 3 arquivos com nós (clientes, empresas e caixas eletrônicos)
- 4 arquivos de transação: um para transações regulares e 3 padrões contendo.
Um script adicional combina transações de padrão com transações regulares, para que não seja possível ver padrões em um gráfico na ordem em que as transações são registradas em um arquivo.
E o que fazer com tudo isso?
No final, temos 4 belos arquivos com nós de gráfico e transações entre eles. Você pode importar para o Neo4J, pode distribuir através do REST, mas o que seu coração desejar, você pode fazer com eles.
Quanto a nós, recebemos um feedback muito positivo dos participantes do hackathon e algumas soluções muito interessantes para encontrar padrões em gráficos massivos.