File size: 2,824 Bytes
942b115
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import pandas as pd

from app.features import FEATURE_COLUMNS, engineer_features


def _raw_frame() -> pd.DataFrame:
    return pd.DataFrame(
        [
            # step, type, amount, nameOrig, oldOrig, newOrig, nameDest, oldDest, newDest
            [1, "TRANSFER", 100.0, "C1", 100.0, 0.0, "C2", 0.0, 0.0],
            [2, "PAYMENT", 50.0, "C1", 0.0, 0.0, "M1", 0.0, 0.0],
            [3, "CASH_OUT", 200.0, "C3", 500.0, 300.0, "C2", 1000.0, 1200.0],
        ],
        columns=[
            "step",
            "type",
            "amount",
            "nameOrig",
            "oldbalanceOrg",
            "newbalanceOrig",
            "nameDest",
            "oldbalanceDest",
            "newbalanceDest",
        ],
    )


def test_engineer_features_adds_all_feature_columns():
    out = engineer_features(_raw_frame())
    for col in FEATURE_COLUMNS:
        assert col in out.columns


def test_type_one_hot_is_mutually_exclusive():
    out = engineer_features(_raw_frame())
    type_cols = [c for c in out.columns if c.startswith("type_")]
    assert (out[type_cols].sum(axis=1) == 1).all()


def test_orig_zero_after_flag_detects_fraud_like_pattern():
    out = engineer_features(_raw_frame())
    row = out[out["nameOrig"] == "C1"].iloc[0]
    assert row["orig_zero_after_flag"] == 1


def test_dest_is_merchant_flag():
    out = engineer_features(_raw_frame())
    row = out[out["nameDest"] == "M1"].iloc[0]
    assert row["dest_is_merchant"] == 1
    row2 = out[out["nameDest"] == "C2"].iloc[0]
    assert row2["dest_is_merchant"] == 0


def test_velocity_only_counts_prior_transactions():
    df = pd.DataFrame(
        [
            [1, "PAYMENT", 10.0, "C1", 100.0, 90.0, "M1", 0.0, 0.0],
            [2, "PAYMENT", 10.0, "C1", 90.0, 80.0, "M1", 0.0, 0.0],
            [3, "PAYMENT", 10.0, "C1", 80.0, 70.0, "M1", 0.0, 0.0],
        ],
        columns=[
            "step",
            "type",
            "amount",
            "nameOrig",
            "oldbalanceOrg",
            "newbalanceOrig",
            "nameDest",
            "oldbalanceDest",
            "newbalanceDest",
        ],
    )
    out = engineer_features(df)
    counts = out.sort_values("step")["orig_prior_txn_count"].tolist()
    assert counts == [0, 1, 2]


def test_balance_consistency_flags_true_when_arithmetic_matches():
    df = pd.DataFrame(
        [[1, "CASH_OUT", 100.0, "C1", 500.0, 400.0, "C2", 200.0, 300.0]],
        columns=[
            "step",
            "type",
            "amount",
            "nameOrig",
            "oldbalanceOrg",
            "newbalanceOrig",
            "nameDest",
            "oldbalanceDest",
            "newbalanceDest",
        ],
    )
    out = engineer_features(df)
    assert out.iloc[0]["orig_balance_consistent"] == 1
    assert out.iloc[0]["dest_balance_consistent"] == 1