Lesson 20 · Finance and Stock Market Analytics
Preparing Clean Financial Datasets for Analysis: Step-by-Step Data Cleaning Guide
Learn how to get and prepare real financial data. Discover how messy data can hurt stock market analysis. Master data cleaning, fixing problems, and best…
- CourseFinance and Stock Market Analytics
- Lesson20 of 16
- Video23 min
- FormatJupyter notebook · 14 code cells
- Data1 dataset
What you'll learn
- Key Financial Data Types for Stock Market Analysis
- Beginner Example 1: Downloading Multi-Ticker OHLCV Data
- Beginner Example 2: Getting Only Adjusted Closing Prices
- Beginner Example 3: Downloading Company List (S&P 500)
- Intermediate Example 1: Cleaning and Filtering One Ticker
- Intermediate Example 2: Calculating Returns and Checking NaN
- Intermediate Example 3: Merging Company Metadata with Prices
- Advanced Example 1: Cleaning a Simulated Real Portfolio
Datasets used in this lesson
Save these next to the notebook. In Google Colab, upload them with the 📁 icon on the left first.
- cleaned_ohlcv.csv148.2 KB
📓 Full notebook
Download .ipynbPreparing Clean Financial Datasets for Analysis#
- Learn how to get and prepare real financial data.
- Discover how messy data can hurt stock market analysis.
- Master data cleaning, fixing problems, and best practices.
- See examples from the real world to improve your skills.
- Build confidence to solve real finance problems yourself.
import pandas as pd
import numpy as np
import yfinance as yf
import warnings
warnings.filterwarnings('ignore')
Key Financial Data Types for Stock Market Analysis#
- Most financial datasets come from real trading data or company reports.
- Common types: price history, trade volume, company fundamentals.
- They can be wide (dates as rows, tickers as columns) or long (each trade/ticker in a row).
- Often contain missing values, bad labels, or odd formats.
- Cleaning is vital to prevent mistakes and get real insight.
Beginner Example 1: Downloading Multi-Ticker OHLCV Data#
- Let us download real daily prices for several tech stocks using yfinance.
- We will reshape and preview the data in a clean, easy-to-use long format.
tickers = ['AAPL','MSFT','GOOGL','AMZN','TSLA']
ohlcv = yf.download(tickers, period='1y', auto_adjust=True, progress=False)
ohlcv = ohlcv.stack(future_stack=True).rename_axis(['Date','Ticker']).reset_index()
ohlcv.columns.name = None
print(ohlcv.shape)
print(ohlcv.head(3))
Beginner Example 2: Getting Only Adjusted Closing Prices#
- Extract only daily adjusted closing prices to keep things simple.
- The result is a convenient wide format with one column per ticker.
df = yf.download(tickers, period='1y', auto_adjust=True, progress=False)
df = df['Close'].reset_index()
df.columns.name = None
print(df.shape)
print(df.head(3))
Beginner Example 3: Downloading Company List (S&P 500)#
- Real analysis often starts by researching lists of companies.
- Load the S&P 500 company list directly from GitHub.
- See basic columns like ticker symbol and sector.
url = 'https://raw.githubusercontent.com/datasets/s-and-p-500-companies/main/data/constituents.csv'
sp500 = pd.read_csv(url)
print(sp500.shape)
print(sp500.head(3))
Intermediate Example 1: Cleaning and Filtering One Ticker#
- Select Apple data only and check for missing trades.
- Real data sometimes has gaps due to holidays or suspensions.
aapl = ohlcv[ohlcv['Ticker'] == 'AAPL'].copy()
print(aapl.isna().sum())
aapl = aapl.dropna()
print('Remaining rows after dropna:', len(aapl))
Intermediate Example 2: Calculating Returns and Checking NaN#
- Add percent daily return to a wide price table.
- Identify where returns are missing or invalid (NaN).
price_df = df.copy()
price_df['AAPL_ret'] = price_df['AAPL'].pct_change() * 100
print(price_df[['Date','AAPL','AAPL_ret']].head())
nan_count = price_df['AAPL_ret'].isna().sum()
print('Missing daily returns:', nan_count)
Intermediate Example 3: Merging Company Metadata with Prices#
- Join S&P 500 company info with price data by ticker.
- Add sector details to each price row.
meta = sp500[['Symbol','GICS Sector']].rename(columns={'Symbol':'Ticker','GICS Sector':'Sector'})
aug_ohlcv = ohlcv.merge(meta, how='left', on='Ticker')
print(aug_ohlcv[['Date','Ticker','Close','Sector']].head(3))
print('Rows with missing sector:', aug_ohlcv['Sector'].isna().sum())
Advanced Example 1: Cleaning a Simulated Real Portfolio#
- Build a portfolio with real buy prices, current prices, and random share counts.
- Calculate percent gain and practice cleaning sector values.
tickers = ['AAPL','MSFT','GOOGL','AMZN','TSLA','NVDA','META','NFLX','JPM','JNJ']
sector_map = {'AAPL':'Tech','MSFT':'Tech','GOOGL':'Tech','AMZN':'Consumer',
'TSLA':'Auto','NVDA':'Tech','META':'Tech','NFLX':'Media',
'JPM':'Finance','JNJ':'Health'}
np.random.seed(42)
data = yf.download(tickers, period='1y', auto_adjust=True, progress=False)['Close']
rows = []
for tk in tickers:
buy = round(float(data[tk].iloc[0]), 2)
cur = round(float(data[tk].iloc[-1]), 2)
rows.append({'ticker': tk, 'shares': int(np.random.randint(5, 100)),
'buy_price': buy, 'cur_price': cur, 'sector': sector_map[tk]})
df_port = pd.DataFrame(rows)
df_port['gain_pct'] = np.round((df_port['cur_price'] - df_port['buy_price']) / df_port['buy_price'] * 100, 2)
print(df_port.head(3))
Advanced Example 2: Handling Missing Real Fundamental Data#
- Download company fundamentals for several big stocks using yfinance.
- Replace missing values with simple defaults or clearly mark them.
big_tickers = ['AAPL','MSFT','GOOGL','AMZN','TSLA','NVDA','META','JPM','JNJ','XOM','WMT','V']
rows = []
for tk in big_tickers:
info = yf.Ticker(tk).info
rows.append({
'ticker': tk,
'sector': info.get('sector', 'Unknown'),
'market_cap': info.get('marketCap'),
'pe_ratio': info.get('trailingPE'),
'eps': info.get('trailingEps'),
'profit_margin':info.get('profitMargins'),
'debt_equity': info.get('debtToEquity')
})
fund_df = pd.DataFrame(rows)
n_missing = fund_df.isnull().sum()
fund_df['debt_equity'] = fund_df['debt_equity'].fillna(-1)
print(n_missing)
print(fund_df.head(3))
Advanced Example 3: Pivoting Data Formats for Analysis#
- Change from long to wide format for matrix-based operations.
- Use pivot() to make each ticker a separate column for quick group statistics.
wide = ohlcv.pivot(index='Date', columns='Ticker', values='Close')
print(wide.head(3))
print('NaN count per ticker:')
print(wide.isnull().sum())
Error Handling Example 1: What If a Column is Missing?#
- Missing columns break cleaning steps if you do not check first.
- Always check .columns before referencing or merging columns.
if 'Close' not in ohlcv.columns:
print('Error: Close column missing from dataset!')
else:
print('Close column present - safe to proceed.')
Error Handling Example 2: Handling All-NaN Rows Before Analysis#
- Empty or all-NaN rows cause bugs in calculations or outputs.
- Use dropna or fillna to preemptively avoid errors in later steps.
before = wide.shape[0]
wide_clean = wide.dropna(how='any')
after = wide_clean.shape[0]
print(f'Removed {before - after} rows with missing data.')
Best Practices: Key Principles in Financial Data Cleaning#
- Always check for major data gaps and inspect summary statistics first.
- Carefully handle missing values, as market datasets often have holes.
- Avoid hard-coding tickers, columns, or index values wherever possible.
- Save cleaned files to new locations to protect original data.
- Clearly document each cleaning step for audit and reproducibility.
# Save your cleaned OHLCV data for future modeling or sharing
save_path = 'cleaned_ohlcv.csv'
aug_ohlcv.to_csv(save_path, index=False)
print(f'File saved: {save_path}')
End-to-End Example: From Raw Multi-Ticker Data to Usable Matrix#
- From long raw format, build a complete, clean wide returns matrix for portfolio modeling.
- Handle missing days, calculate returns, and get ready for backtests.
# Pivot long OHLCV data to wide format by close price
returns_wide = ohlcv.pivot(index='Date', columns='Ticker', values='Close')
# Compute daily percent returns for every ticker
returns = returns_wide.pct_change() * 100
# Drop first row (NaNs from pct_change), then all rows with any missing values
returns = returns.dropna().reset_index()
print(returns.head(3))
print(f'Final shape for portfolio modeling: {returns.shape}')
YouTube Call-to-Action#
- Want more step-by-step finance data cleaning? Search "FinPyLab Clean Data" on YouTube.
- Like and subscribe for more real market Python tutorials.
Found this useful?
All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.



