Bonne après-midi. Je m'appelle Nikita Bashun, je travaille comme analyste de données dans le groupe d'entreprises "Lucky". Mon histoire portera sur la façon dont nous, une équipe de trois personnes, avons créé de toutes pièces un système anti-fraude pour le service de réservation de voyages.
introduction
Celui qui sait tromper jadis trompera plusieurs fois.
Lope de Vega
La fraude dans notre cas est une situation où un conducteur trompe une entreprise. Fraude pour obtenir de l'argent.
, , 25, Delphi. . , . , . …
— MVP, .
, :
- . ( «-» ), , . ;
- . — , ( , ). -, 200 .
- , — « »:
- , (, 0% );
- , -.
:
- — , , , ;
- - ( ) — , , ;
- — , , ,
- False Positive, False Negative . :
- , ( , !);
- .
- . ;
- . , — . , , , . - , … .
SQL- DWH, . . , , «»:
WHERE susp = 1 --
AND finished_orders >= 3 --
AND cancelled >= 3 -- ,
AND dist_fin_drivers <= 2 --
AND ok <= 2 -- 2-
, .
. « » . , ? -. , .
python. pandas, postgres, Google ( ). , , Apache Airflow.
API .
:
credentials = ServiceAccountCredentials.from_json_keyfile_dict(
config.crd,
['https://www.googleapis.com/auth/spreadsheets',
'https://www.googleapis.com/auth/drive'])
httpAuth = credentials.authorize(httplib2.Http())
service = googleapiclient.discovery.build('sheets', 'v4', http=httpAuth)
sheet = service.spreadsheets()
:
base_range = f'{city_name}!A{ss_row + 1}:Z{ss_row + reserved_rows}'
sheet.values().append(spreadsheetId=spreadsheetid,
range=base_range,
body={"values": df_pos.values.tolist()},
valueInputOption='RAW').execute()
:
range_from_ss = f'{city_name}!A{ss_row}:S{ss_row + reserved_rows}'
data_from_ss = service.spreadsheets().values().get(
spreadsheetId=spreadsheetid,
range=range_from_ss).execute().get('values', [])
data_from_ss = pd.DataFrame(data_from_ss)
data_from_ss_cols = ['id', '', '']
data_from_ss = data_from_ss.loc[1:, data_from_ss_cols]
PG:
vls_ss = ','.join([f"""({', '.join([f(d[c]) for c in data_from_ss_cols])}
)""" for d in data_from_ss.to_dict('rows')])
sql_update = f"""
WITH updated as (
UPDATE fraud_billing
SET resolution = tb.resolution,
comment=tb.comment,
dt = NOW()
FROM (VALUES {vls_ss}) AS tb(fraud_billing_id, resolution, comment)
WHERE fraud_billing.fraud_billing_id = CAST(tb.fraud_billing_id AS INTEGER)
AND ((fraud_billing.resolution IS NULL AND tb.resolution IS NOT NULL)
OR (fraud_billing.comment IS NULL AND tb.comment IS NOT NULL)
OR (fraud_billing.comment IS NOT NULL AND tb.comment IS NOT NULL
AND fraud_billing.comment <> tb.comment)
OR (fraud_billing.resolution IS NOT NULL AND tb.resolution IS NOT NULL
AND fraud_billing.resolution <> tb.resolution)
)
RETURNING {alias_cols_text_with_id}
)
INSERT INTO fraud_billing_history ({cols_text_with_id})
SELECT {cols_text_with_id}
FROM updated;
"""
crs_postgres.execute(sql_update)
con_postgres.commit()
postgres :
- ;
- .
:
( , ).
, :
— .
: , , .
.
, . , , — . «» .
FP- , .
— , , . .
« ». , , :
- ;
- ;
- ;
- — .
.
, . , , , , . - :
, , — .
Google Spreadsheets. . , :
- , «» ;
- API — ;
- ;
- , .
. , — :
- . - , - , - . , . ;
- . , , :
- - , ;
- - ;
- - , ;
- - .
, , . , «».
— , . — , . !
, ?
- . . , «» , . ;
- . , . , .
( ) 35%. — 25%. , — — , . : , , , . .
:
- 15 ;
- 6800 ;
- 500 .
Mais le succès le plus important est la réduction progressive des cas de suspicion eux-mêmes dans de nombreuses villes. Après tout, idéalement, nous ne voulons pas en attraper plus , nous ne voulons rien attraper .
Conclusion
J'ai essayé de décrire les principales fonctionnalités et principes du système anti-fraude, ainsi que les difficultés que nous avons rencontrées. Les plans comprennent: l'utilisation du ML pour optimiser la recherche, la création d'un système de surveillance des sanctions (maintenant il en est à un stade initial), l'amélioration de l'interface pour les gestionnaires, la création de rapports dynamiques, le développement de nouveaux modèles, et bien plus encore.
Après tout, nous ne sommes qu'au début du voyage.