Mathew K Analytics

Lesson 1 · Python for Banking and Finance

Python Basics for Banking

Learn how to use Python to solve real-world problems in banking. Work with synthetic banking transaction data to understand customer activity. Discover…

⬇ Download notebookOpen in Colab ↗

What you'll learn

Data

No separate download needed — the notebook creates or downloads everything it uses.

📓 Full notebook

Download .ipynb

Python Basics for Banking#

  • Learn how to use Python to solve real-world problems in banking.
  • Work with synthetic banking transaction data to understand customer activity.
  • Discover fundamental and intermediate skills, from loading and exploring data to best practices.
  • Build practical skills for banking analysis you can use at work or for projects.
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings('ignore')

Understanding Banking Data in Python#

  • Banking data includes transactions, accounts, and customer info.
  • Transaction tables usually show each movement of money: customer, amount, type, when, and channel.
  • Account tables record details about accounts: type, open date, and ID.
  • Beginners often forget to check data types or miss relationships between tables.
  • Getting familiar with structure helps avoid errors and confusion.
np.random.seed(42)  # Set seed for reproducibility
n_transactions = 1000
n_customers = 200
df = pd.DataFrame({
    'transaction_id': range(1, n_transactions + 1),
    'customer_id': np.random.choice([f'CUST_{i:04d}' for i in range(1, n_customers + 1)], n_transactions),
    'amount': np.round(np.random.normal(150, 60, n_transactions), 2),
    'transaction_type': np.random.choice(['Debit', 'Credit'], n_transactions),
    'channel': np.random.choice(['ATM', 'Online', 'Branch', 'POS'], n_transactions),
    'date': pd.date_range(start='2024-01-01', periods=n_transactions, freq='h')
})
print(df.shape)
print(df.head(3))
(1000, 6)
   transaction_id customer_id  amount transaction_type channel  \
0               1   CUST_0103  238.77           Credit     ATM   
1               2   CUST_0180  269.17           Credit     POS   
2               3   CUST_0093   58.62           Credit  Online   

                 date  
0 2024-01-01 00:00:00  
1 2024-01-01 01:00:00  
2 2024-01-01 02:00:00  
customer_ids = [f'CUST_{i:04d}' for i in range(1, 201)]
customers = pd.DataFrame({
    'customer_id': customer_ids,
    'segment': ['Retail'] * 150 + ['Business'] * 50,
    'region': ['Metro'] * 100 + ['Regional'] * 100
})
print(customers.shape)
print(customers.head(3))
(200, 3)
  customer_id segment region
0   CUST_0001  Retail  Metro
1   CUST_0002  Retail  Metro
2   CUST_0003  Retail  Metro
np.random.seed(42)  # Set seed for reproducibility
accounts = pd.DataFrame({
    'account_id': [f'ACC_{i:05d}' for i in range(1, 201)],
    'customer_id': customer_ids,
    'account_type': np.random.choice(['Savings', 'Cheque', 'Credit'], size=200),
    'open_date': pd.date_range(start='2015-01-01', periods=200, freq='30D')
})
print(accounts.shape)
print(accounts.head(3))
(200, 4)
  account_id customer_id account_type  open_date
0  ACC_00001   CUST_0001       Credit 2015-01-01
1  ACC_00002   CUST_0002      Savings 2015-01-31
2  ACC_00003   CUST_0003       Credit 2015-03-02
print(df.columns)
Index(['transaction_id', 'customer_id', 'amount', 'transaction_type',
       'channel', 'date'],
      dtype='object')
print(df['transaction_type'].value_counts())
transaction_type
Credit    503
Debit     497
Name: count, dtype: int64
avg_amount = df['amount'].mean()
print('Average transaction amount:', avg_amount)
Average transaction amount: 151.70208000000002
customer_txn_counts = df['customer_id'].value_counts().head(5)
print('Top 5 customers by transaction count:')
print(customer_txn_counts)
Top 5 customers by transaction count:
customer_id
CUST_0190    13
CUST_0099    13
CUST_0113    11
CUST_0161    11
CUST_0090    10
Name: count, dtype: int64
channel_stats = df.groupby('channel')['amount'].agg(['mean', 'max', 'min'])
print('Amount stats by channel:')
print(channel_stats)
Amount stats by channel:
               mean     max    min
channel                           
ATM      156.043534  338.52 -12.75
Branch   151.465565  335.64  -1.76
Online   151.310042  340.47 -64.09
POS      147.687480  292.11   1.89
monthly_totals = df.resample('M', on='date')['amount'].sum()
print('Total transaction amount by month:')
print(monthly_totals)
Total transaction amount by month:
date
2024-01-31    114493.50
2024-02-29     37208.58
Freq: ME, Name: amount, dtype: float64
result = pd.merge(df, customers, on='customer_id', how='left')
print('Merged transaction and customer data:')
print(result.head(3))
Merged transaction and customer data:
   transaction_id customer_id  amount transaction_type channel  \
0               1   CUST_0103  238.77           Credit     ATM   
1               2   CUST_0180  269.17           Credit     POS   
2               3   CUST_0093   58.62           Credit  Online   

                 date   segment    region  
0 2024-01-01 00:00:00    Retail  Regional  
1 2024-01-01 01:00:00  Business  Regional  
2 2024-01-01 02:00:00    Retail     Metro  
pivot = df.pivot_table('amount', index='transaction_type', columns='channel', aggfunc='mean')
print('Pivot table: mean amount by type and channel')
print(pivot)
Pivot table: mean amount by type and channel
channel                  ATM      Branch      Online         POS
transaction_type                                                
Credit            154.920698  146.796560  150.172212  150.123824
Debit             157.100803  156.210488  152.355366  144.780965
largest_txn = df.loc[df['amount'].idxmax()]
print('Largest transaction:')
print(largest_txn)
Largest transaction:
transaction_id                       93
customer_id                   CUST_0111
amount                           340.47
transaction_type                  Debit
channel                          Online
date                2024-01-04 20:00:00
Name: 92, dtype: object
debit_percent = df['transaction_type'].value_counts(normalize=True)['Debit'] * 100
print(f'Percentage of Debit transactions: {debit_percent:.2f}%')
Percentage of Debit transactions: 49.70%
print(df.describe())
       transaction_id       amount                           date
count     1000.000000  1000.000000                           1000
mean       500.500000   151.702080  2024-01-21 19:29:59.999999744
min          1.000000   -64.090000            2024-01-01 00:00:00
25%        250.750000   111.372500            2024-01-11 09:45:00
50%        500.500000   153.535000            2024-01-21 19:30:00
75%        750.250000   195.162500            2024-02-01 05:15:00
max       1000.000000   340.470000            2024-02-11 15:00:00
std        288.819436    63.022399                            NaN
summary = df.groupby(['customer_id', 'transaction_type'])['amount'].sum().unstack(fill_value=0)
summary['net_flow'] = summary['Credit'] - summary['Debit']
print('Net flow (Credit - Debit) per customer:')
print(summary.head())
Net flow (Credit - Debit) per customer:
transaction_type  Credit   Debit  net_flow
customer_id                               
CUST_0001         471.49  611.67   -140.18
CUST_0002         726.12  193.86    532.26
CUST_0003         388.82  783.31   -394.49
CUST_0004         444.53  213.26    231.27
CUST_0005         217.90  412.92   -195.02
debit_channels = df[df['transaction_type'] == 'Debit']['channel'].value_counts()
print('Most common channels for Debits:')
print(debit_channels)
Most common channels for Debits:
channel
ATM       137
Branch    123
Online    123
POS       114
Name: count, dtype: int64
try:
    no_column = df['balance']
except KeyError as e:
    print('Error:', e)
Error: 'balance'
try:
    negative_txn = df[df['amount'] < 0]
    if negative_txn.empty:
        print('All transaction amounts are positive.')
    else:
        print('Some transaction amounts are negative:')
        print(negative_txn.head())
except Exception as ex:
    print('An error occurred:', ex)
Some transaction amounts are negative:
     transaction_id customer_id  amount transaction_type channel  \
94               95   CUST_0024   -4.38           Credit  Online   
165             166   CUST_0170  -64.09           Credit  Online   
231             232   CUST_0068   -4.69           Credit     ATM   
297             298   CUST_0161  -12.75           Credit     ATM   
304             305   CUST_0166   -1.76            Debit  Branch   

                   date  
94  2024-01-04 22:00:00  
165 2024-01-07 21:00:00  
231 2024-01-10 15:00:00  
297 2024-01-13 09:00:00  
304 2024-01-13 16:00:00  
try:
    idx = df[df['date'] == '2025-01-01'].index[0]
    print('Row found at index:', idx)
except IndexError:
    print('No transactions found for that date.')
No transactions found for that date.
assert df['amount'].isnull().sum() == 0, 'No missing amounts allowed!'
# Always review datatypes early
print(df.dtypes)
transaction_id               int64
customer_id                 object
amount                     float64
transaction_type            object
channel                     object
date                datetime64[ns]
dtype: object
# Clean data: ensure all channel categories are expected
expected_channels = {'ATM', 'Online', 'Branch', 'POS'}
actual_channels = set(df['channel'].unique())
if not actual_channels.issubset(expected_channels):
    print('Unexpected channel values found:', actual_channels - expected_channels)
else:
    print('All channel values are as expected.')
All channel values are as expected.
# End-to-End: What is the most profitable business region?
merged = pd.merge(df, customers, on='customer_id')
region_profit = merged[merged['segment'] == 'Business'].groupby('region')['amount'].sum()
best_region = region_profit.idxmax()
print('Business segment profit by region:')
print(region_profit)
print('Most profitable business region is:', best_region)
Business segment profit by region:
region
Regional    36894.26
Name: amount, dtype: float64
Most profitable business region is: Regional

Great job: What next?#

  • You learned how to use Python for banking data from setup to advanced analytics.
  • Practice designing your own banking DataFrame and write end-to-end solutions.
  • Watch our YouTube Python banking playlist for deeper dives and real case studies.

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.