Nubank Analytics Engineer Case Resolution
Para a resolução do case proposto, as tabelas enviadas em anexo foram subidas para o
ambiente do Google BigQuery, resultando no seguinte dataset:
Apesar de alguns nomes de tabela terem sido modificados, os campos e estruturas se
mantiveram iguais aos arquivos enviados e schema.
Resolução problema 1:
Para dar suporte à Jane a seguinte query foi criada em linguagem SQL adaptada para
BigQuery:
---- BALANÇO MENSAL DA CONTA (ACCOUNT MONTHLY BALANCE)
---- SALDO NA CONTA AO FINAL DO MÊS
--- VARIÁVEIS
-- MONTH
-- CUSTOMER
-- TOTAL TRANSFER IN
-- TOTAL TRANSFER OUT
-- ACCOUNT MONTHLY BALANCE
-- PERÍODO:
-- JAN/2020 A DEZ/2020
WITH
-- MONTAR AS TRANSAÇÕES DE PIX
PIX AS (
SELECT
MT.action_month,
ACC.customer_id,
SUM(CASE
WHEN PIX.in_or_out = 'pix_in' THEN PIX.pix_amount
ELSE
0
END
) AS TOTAL_PIX_IN,
SUM(CASE
WHEN PIX.in_or_out = 'pix_out' THEN PIX.pix_amount
ELSE
0
END
) AS TOTAL_PIX_OUT
FROM
`data-warehouse-environment.TABLES.ACCOUNTS` AS ACC
INNER JOIN
`data-warehouse-environment.TABLES.PIX_MOVEMENTS` AS PIX
ON
PIX.account_id = ACC.account_id
INNER JOIN
`data-warehouse-environment.TABLES.TIME` AS TM
ON
TM.time_id = PIX.pix_completed_at
INNER JOIN
`data-warehouse-environment.TABLES.YEAR` AS YR
ON
YR.year_id = TM.year_id
INNER JOIN
`data-warehouse-environment.TABLES.MONTH` AS MT
ON
MT.month_id = TM.month_id
WHERE
PIX.status = 'completed'
AND YR.action_year = 2020
GROUP BY
1,
2 ),
-- MONTAR AS TRANSAÇÕES DE ENTRADA POR TRANSFERÊNCIA
TRANSFER_IN AS (
SELECT
MT.action_month,
ACC.customer_id,
SUM(TIN.amount) AS TOTAL_TRASFER_IN
FROM
`data-warehouse-environment.TABLES.ACCOUNTS` AS ACC
INNER JOIN
`data-warehouse-environment.TABLES.TRANSFER_INS` AS TIN
ON
TIN.account_id = ACC.account_id
INNER JOIN
`data-warehouse-environment.TABLES.TIME` AS TM
ON
TM.time_id = TIN.transaction_completed_at
INNER JOIN
`data-warehouse-environment.TABLES.YEAR` AS YR
ON
YR.year_id = TM.year_id
INNER JOIN
`data-warehouse-environment.TABLES.MONTH` AS MT
ON
MT.month_id = TM.month_id
WHERE
TIN.status = 'completed'
AND YR.action_year = 2020
GROUP BY
1,
2 ),
-- MONTAR AS TRANSAÇÕES DE SAÍDA POR TRANSFERÊNCIA
TRANSFER_OUT AS (
SELECT
MT.action_month,
ACC.customer_id,
SUM(TOUT.amount) AS TOTAL_TRASFER_OUT
FROM
`data-warehouse-environment.TABLES.ACCOUNTS` AS ACC
INNER JOIN
`data-warehouse-environment.TABLES.TRANSFER_OUTS` AS TOUT
ON
TOUT.account_id = ACC.account_id
INNER JOIN
`data-warehouse-environment.TABLES.TIME` AS TM
ON
TM.time_id = TOUT.transaction_completed_at
INNER JOIN
`data-warehouse-environment.TABLES.YEAR` AS YR
ON
YR.year_id = TM.year_id
INNER JOIN
`data-warehouse-environment.TABLES.MONTH` AS MT
ON
MT.month_id = TM.month_id
WHERE
TOUT.status = 'completed'
AND YR.action_year = 2020
GROUP BY
1,
2)
-- PARTIR DA TABELA DE CLIENTES (COSTUMERS) E MESES, POIS PODEM HAVER
CLIENTES QUE NÃO POSSUEM TRANSAÇÕES DURANTE DETERMINADO MÊS.
IMPORTANTE TAMBÉM DEFINIR QUEM É O CLIENTE E SUA LOCALIZAÇÃO.
,
TRANSACTIONS AS (
SELECT
CAST(MT.action_month AS INT64) AS month,
CM.customer_id,
CM.first_name,
CM.last_name,
CM.cpf,
CM.country_name,
ST.state,
CT.city,
IFNULL(PIX.TOTAL_PIX_IN+TIN.TOTAL_TRASFER_IN,
0) AS TOTAL_TRANSFER_IN,
IFNULL(PIX.TOTAL_PIX_OUT+TOUT.TOTAL_TRASFER_OUT,
0) AS TOTAL_TRANSFER_OUT,
IFNULL(PIX.TOTAL_PIX_IN,
0)+IFNULL(TIN.TOTAL_TRASFER_IN,
0)-IFNULL(PIX.TOTAL_PIX_OUT,
0)-IFNULL(TOUT.TOTAL_TRASFER_OUT,
0) AS ACCOUNT_MOTHLY_BALANCE
FROM
`data-warehouse-environment.TABLES.CUSTOMERS` AS CM,
`data-warehouse-environment.TABLES.MONTH` MT
INNER JOIN
`data-warehouse-environment.TABLES.CITY` AS CT
ON
CT.city_id = CM.customer_city
INNER JOIN
`data-warehouse-environment.TABLES.STATE` AS ST
ON
ST.state_id = CT.state_id
LEFT JOIN
PIX AS PIX
ON
PIX.customer_id = CM.customer_id
AND MT.action_month = PIX.action_month
LEFT JOIN
TRANSFER_IN TIN
ON
TIN.customer_id = CM.customer_id
AND TIN.action_month = MT.action_month
LEFT JOIN
TRANSFER_OUT TOUT
ON
TOUT.customer_id = CM.customer_id
AND TOUT.action_month = MT.action_month
ORDER BY
2,
1)
--DESENVOLVIMENTO DA PARTE QUE CALCULA O SALDO EM CADA MÊS PARA CADA
CLIENTE.
SELECT
month,
customer_id,
first_name,
last_name,
cpf,
country_name,
state,
city,
TOTAL_TRANSFER_IN,
TOTAL_TRANSFER_OUT,
SUM(ACCOUNT_MOTHLY_BALANCE) OVER (PARTITION BY customer_id ORDER BY
month ROWS BETWEEN 12 PRECEDING AND CURRENT ROW) AS
ACCOUNT_MOTHLY_BALANCE
FROM
TRANSACTIONS
Resolução problema 2:
Para remodelagem do Data Warehouse minha proposta constituiria na criação de datas
warehouses divididos por unidades de negócios (por exemplo: banco, investimento, seguro de
vida, etc), contendo dentro dos mesmos sanbox data devidamente arquitetadas e governadas
(com documentação e em casos de conceitos de negócio, glossários de dados), divididas em 4
tipos:
- sandbox de tabelas de dados provindos de cadastro (sandbox REF_BU), onde todos os
dados cadastrais relativos a um único assunto são unidos;
- sandbox de tabelas de movimentações, contendo conceito de negócio e enriquecida com
dados cadastrais (sandbox TRU_BU);
- sandbox de modelagem (sandbox TRU_BU_MODELS);
- sandbox de dashboards, contendo as tabelas referentes a alimentação de dashboards (se for
no Google BQ, indicaria criar um para cada dashboard devido a possibilidade restrição de
acesso ao dash poder ser realizada através da restrição ao sanbox).
As data warehouses existiriam em versão de homologação e produção, possuíram somente
dados em último versionamento (modificação mais recente) e seriam particionadas para melhor
performance e menor custo.
As tabelas teriam nomes de campos padronizados para fácil identificação do tipo e sobre qual
assunto se refere e todos os campos seriam padronizados para letras maiúsculas.
Além dos citados acima, proporia repositórios exclusivos de áreas da companhia
(SANDBOX_AREA_NAME), onde poderiam ser criadas tabelas específicas para estudos da
área, não sendo necessária que as mesmas sejam governadas, pois utilizariam dados
provindos de tabelas governadas, conforme forem disponibilizadas.
Devido a atuação global da companhia, todas a tabelas seriam clusterizadas por país e para
facilitar estudo globais de Market Share, tabela de movimentações globais seriam criadas
dentro da sandbox de movimentações de cada negócio, adaptadas sempre para cada
necessidade de negócio e sem adição de pontos particulares de alguma região. Para negócios
onde há particularidades, como o caso do PIX ou LGPD brasileiro, tabelas de movimentações
seriam criadas para cada um desses negócios com as tags de ocultação aplicadas, porém na
tabela de movimentação global somente os saldos de entrada e saídas estariam presentes e os
códigos de id internos, para que nenhuma lei seja infringida.
Para que não aja prejuízo para os atuais processos e analises da companhia, as tabelas atuais
e data warehouse não seriam descontinuados ou modificados de imediato. Somente após a
tabela finalizada, homologada, com toda documentação realizada, divulgação da mesma
realizada dentro da companhia e divulgação de pontos focais para devidas dúvidas sobre, que
um período de adaptação e mudança dos processos seria iniciado, com acompanhamento da
área de governança sobre a permanecia de utilização da tabela antiga pelos pares, e assim
que a adesão ultrapassar um baseline acordado do total de colaboradores utilizando-as que
seriam comunicados todos os mebros da companhia da descontinuidade da mesma no
repositório Data Warehouse atual. Sabemos que esse é um momento delicado e para que as
novas tabelas sejam atraentes, poderiam ser realizados apresentações curtas sobre as
mesmas para grupos ou áreas, demonstrando suas vantagens, utilizando para isso criações de
dashboards demonstrando as informações que podem ser retiradas da mesma, e menores
custos ou tempo de processamento nas consultas destas. Há sempre a necessidade de se
mostrar as vantagens de uma cultura data driven e como tabelas governadas e documentadas
permitem o empoderamento dos analistas, além de que com data warehouses específicos para
cada negócio cria-se uma facilidade em se descobrir as informações que a companhia tem
sobre o mesmo, ampliando possibilidades de análises por parte dos analistas.
Para exemplificar minha solução reproduzi a mesma nos dados enviados, ficando os data
warehouses, repositórios e tabelas dessa maneira:
Figura 1: Data Warehouses criados na BigQuery
Figura 2: Sandbox de cadastro criados com a nomenclatura REF_BU, de movimentações com
nomenclatura TRU_BU e de modelos com nomenclatura TRU_BU_MODELS
Figura 3: Tabelas governadas criadas sobre cada tipo de cadastro (Contas, Clientes e Período). Tabelas
de movimentações de produtos específicos (Pix e Transferência tradicional) e a global
Todas as tabelas possuem nomenclatura de campos padronizados para fácil identificação do
tipo de campo (DSC para campos de descrição de de/para, ID para codificação, NUM para
campos numéricos, NME para campos string contendo nomes próprios de países ou pessoas e
etc, ABBR para siglas, DAT para datas, etc). Em todas as tabelas um mesmo campo possui o
mesmo nome e se referente a um mesmo assunto, todos possuem a descrição do assunto no
final do nome (exemplo: todos os campos relativos ao cadastro de um cliente possuem
CUSTOMER no final do nome).
Tabela de Cadastro de Clientes
Tabela Cadastro de Contas
Tabela Cadastro de Períodos de Tempo
Tabela de movimentações PIX
Tabela de movimentações de Transferências
Tabela global de transações diárias (somente transações completas)
Por se tratarem de tabelas pequenas, com somente dados do Brasil, e de uso somente para
exemplo, não foi realizada a clusterização ou particionamento de todas as tabelas e nem
adicionado tags de ocultação de acordo com a LGPD.
Para efeito de comparação de custo e eficiência, a diferença de tamanho de processamento
entre a solução do primeiro problema proposto e uma solução utilizando as tabelas governadas
para o mesmo problema seriam da ordem de quase 40 MB (de 47,3 MB para 1,8 MB), e a
query reduziria para essa complexidade:
WITH
TRANSACTIONS AS (
SELECT
CAST(MT.action_month AS INT64) AS MONTH,
CM.ID_CUSTOMER,
CM.NME_CUSTOMER,
CM.NUM_IDENTIFICATION_CUSTOMER,
CM.NME_COUNTRY_CUSTOMER,
CM.ABBR_STATE_CUSTOMER,
CM.NME_CITY_CUSTOMER,
IFNULL(GLO.AMOUNT_IN,
0) AS TOTAL_TRANSFER_IN,
IFNULL( GLO.AMOUNT_OUT,
0) AS TOTAL_TRANSFER_OUT,
IFNULL(GLO.AMOUNT_IN,
0)-IFNULL(GLO.AMOUNT_OUT,
0) AS ACCOUNT_MOTHLY_BALANCE
FROM
`bu-self-service-bank-
prd.REF_BANK_CUSTOMERS.TB_CUSTOMER_BASE_DATA` AS CM,
`data-warehouse-environment.TABLES.MONTH` MT
LEFT JOIN
`bu-self-service-bank-
prd.TRU_BANK_FINANCIAL_TRANSACTIONS.TB_MOV_GLOBAL_TRANSACTIONS` AS GLO
ON
CM.ID_CUSTOMER = GLO.ID_CUSTOMER
AND MT.action_month = GLO.NUM_MONTH_COMPLETED_TRANSACTION
ORDER BY
2,
1 )
SELECT
MONTH,
ID_CUSTOMER,
NME_CUSTOMER,
NME_COUNTRY_CUSTOMER,
ABBR_STATE_CUSTOMER,
NME_CITY_CUSTOMER,
TOTAL_TRANSFER_IN,
TOTAL_TRANSFER_OUT,
SUM(ACCOUNT_MOTHLY_BALANCE) OVER (PARTITION BY ID_CUSTOMER ORDER BY
month ROWS BETWEEN 12 PRECEDING AND CURRENT ROW) AS
ACCOUNT_MOTHLY_BALANCE
FROM
TRANSACTIONS
Resolução Problema 3:
Para auxiliar Pepino e Jane na análise da performance do PIX eu proporia os seguintes
indicadores e porquês:
1. Penetração: para verificar a adesão de nossos clientes ao novo produto, calculado pela
divisão do total de clientes que já realizaram PIX sobre o total de clientes;
2. Participação no total de transações realizadas: verificar a distribuição entre transações
realizadas e a parte que foi realizada via PIX;
3. Participação no total de valores de transações realizadas: verificar a distribuição do
montante nas transações realizas e a parte que foi realizada via PIX;
4. Total de transações realizadas via PIX: número absoluto de transações para verificar
volume;
5. Total de clientes utilizando PIX: número absoluto de clientes utilizando PIX para
verificar volume de clientes.
6. Média de PIX realizados por cliente e valor médio de PIX realizados: indicadores
utilizados para entender no período de tempo escolhido o volume e valor médio por
cliente de transações via PIX, podendo comparar com as mesmas métricas aplicadas
para transações por transferência tradicional, analisando assim a demanda por cada
um, se existe uma diferente de ticket médio entre os mesmos, acompanhar a migração
dos clientes para o novo método de transferência, comparando com os valores
históricos das métricas, entendo assim qualquer mudança de comportamento oriunda
do novo produto.
Todos os indicadores propostos podem ser aplicados em série temporal, para verifica-los
agrupados por alguma medida de tempo (mês, dia, ano, semana, etc), por localização (Estado
da federação ou Município) e por tipo de PIX (se entrada ou saída de valores, podendo assim
se a adesão é mais forte para pagamento ou recebimento), Comparações com dados históricos
e outros métodos de transferência de valores são indicadas.
Uma proposta de dashboard simples de acompanhamento seria a seguinte (um pdf anexo
possui a tela para melhor visualização):