Table of Contents
Introduction
What Is the Mode—and Why Banks Care
Core Methods to Compute the Mode in Python
Real-World Scenario: Detecting Suspicious Transaction Amounts
Time and Space Complexity
Complete, Production-Ready Implementation
Best Practices & Quick Wins
Conclusion
Introduction
In banking systems, patterns reveal truth—and few patterns are as telling as the mode: the most frequently occurring value in a dataset. While averages smooth out anomalies, the mode highlights repetition, making it a powerful tool for spotting fraud, system errors, or policy violations. This guide shows you how to compute the mode correctly and efficiently in Python—with a real-world banking use case, robust error handling, and zero tolerance for bugs.
What Is the Mode—and Why Banks Care
The mode is the value that appears most often in a list. A dataset can have:
In banking, the mode helps detect:
Repeated micro-transactions (e.g., $0.99) used to test stolen cards
Duplicate payment amounts from system glitches
Common round-dollar transfers that may indicate money laundering
Unlike mean or median, the mode exposes behavioral repetition—exactly what fraud analysts need.
Core Methods to Compute the Mode in Python
1. Using statistics.mode()
(Simple but Limited)
import statistics
try:
mode_val = statistics.mode(data)
except statistics.StatisticsError:
mode_val = None # No unique mode
Built-in and clean—but fails if there’s no single mode.
2. Manual Counting with collections.Counter
(Robust & Flexible)
from collections import Counter
def find_mode(arr):
if not arr:
return None
counts = Counter(arr)
max_count = max(counts.values())
modes = [k for k, v in counts.items() if v == max_count]
return modes[0] if len(modes) == 1 else modes # Return single or list
Handles multimodal data, empty inputs, and custom logic.
Real-World Scenario: Detecting Suspicious Transaction Amounts
Problem
Your bank’s fraud detection system logs transaction amounts. You notice many transactions of $49.99—is this a pricing pattern or a red flag?
Goal
Find the most frequent transaction amount in the last hour to flag potential testing behavior by fraudsters.
Requirements
Handle empty or single-transaction windows
Support multiple modes (e.g., both $9.99 and $49.99 are common)
Never crash on malformed data
Return results instantly for real-time alerts
Time and Space Complexity
Time: O(n) — you must count every transaction once.
Space: O(n) in worst case (all values unique), but typically much less.
Using Counter
is both fast and memory-efficient for real-world banking data.
Avoid sorting-based approaches—they’re slower (O(n log n)
) and unnecessary.
Complete, Production-Ready Implementation
from collections import Counter
from typing import List, Union, Optional
def get_transaction_mode(amounts: List[Union[int, float]]) -> Optional[Union[float, List[float]]]:
"""
Find the mode(s) of transaction amounts for fraud detection.
Args:
amounts: List of transaction amounts (e.g., [49.99, 9.99, 49.99, 100.0])
Returns:
- A single float if one mode exists
- A list of floats if multiple modes exist
- None if input is empty
Example:
get_transaction_mode([10, 20, 20, 30]) → 20.0
get_transaction_mode([5, 5, 10, 10]) → [5.0, 10.0]
"""
if not amounts:
return None
# Count frequencies
counter = Counter(amounts)
max_freq = max(counter.values())
# Get all values with max frequency
modes = [float(val) for val, freq in counter.items() if freq == max_freq]
# Return single value if unimodal, else list
return modes[0] if len(modes) == 1 else sorted(modes)
# Example: Fraud detection in banking
if __name__ == "__main__":
hourly_transactions = [49.99, 9.99, 49.99, 100.0, 49.99, 25.50]
suspicious = [1.00, 1.00, 5.00, 5.00]
empty_window = []
print("Top transaction amount:", get_transaction_mode(hourly_transactions))
print("Multiple common amounts:", get_transaction_mode(suspicious))
print("No transactions:", get_transaction_mode(empty_window))
![qa]()
Best Practices & Quick Wins
Use Counter
—It’s faster and clearer than manual loops.
Handle multimodal cases—fraud often involves multiple repeated amounts.
Return None
for empty input—never assume data exists.
Convert to float
consistently—avoids type confusion in financial systems.
Don’t use statistics.mode()
in production—it throws on multimodal data.
Never log raw transaction lists—only report aggregated modes.
Conclusion
In banking, the mode isn’t just a statistic—it’s a signal. Whether it’s $0.99 test charges or repeated $500 transfers, the most frequent value often reveals intent. By using a robust, flexible mode function like get_transaction_mode
, your fraud detection system gains:
When every transaction counts, the mode ensures you’re watching the right one.