Lesson 16 · Python for Retail E-commerce Analytics
How to Identify Missing and Invalid Retail Records Using Python for E-commerce Analytics
In this lesson, we tackle the vital issue of detecting missing and invalid data in retail and e-commerce datasets. Quality data is essential for analyzing…
- CoursePython for Retail E-commerce Analytics
- Lesson16 of 43
- Video20 min
- FormatJupyter notebook · 18 code cells
What you'll learn
Data
No separate download needed — the notebook creates or downloads everything it uses.
📓 Full notebook
Download .ipynbIdentifying Missing and Invalid Retail Records#
- In this lesson, we tackle the vital issue of detecting missing and invalid data in retail and e-commerce datasets.
- Quality data is essential for analyzing sales, inventory, customer behavior, and making sound business decisions.
- You will learn how to systematically find, interpret, and address gaps or errors in retail records to ensure accurate analysis.
- Mastering these techniques helps teams avoid costly mistakes and unlock trusted sales or marketing insights.
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings('ignore')
Core Concepts in Retail Analytics Data#
- Retail datasets reflect real-world transactions, orders, products, and customer behavior.
- Sales data combines item quantity, unit price, and often customer or time details.
- Missing data can obscure revenue, mask popular products, or lead to false inventory signals.
- Common data issues include blank fields, negative values, date errors, or duplications.
- Beginner analysts may misinterpret missing prices, mix up quantities, or overlook invalid identifiers.
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/00502/online_retail_II.xlsx'
df = pd.read_excel(url, sheet_name='Year 2010-2011')
df['InvoiceDate'] = pd.to_datetime(df['InvoiceDate'])
print(df.shape)
print(df.head(3))
print(df.columns.tolist())
missing_summary = df.isnull().sum()
print(missing_summary)
num_missing = df.isnull().sum().sum()
print(f'Total missing values in dataset: {num_missing}')
missing_rows = df[df.isnull().any(axis=1)]
print(f'Rows with missing data: {missing_rows.shape[0]}')
print(missing_rows.head(2))
df['IsIncomplete'] = df.isnull().any(axis=1)
print(df[['Invoice', 'StockCode', 'IsIncomplete']].head(5))
percent_incomplete = df['IsIncomplete'].mean() * 100
print(f'Percentage of incomplete records: {percent_incomplete:.2f}%')
invalid_quant = df[df['Quantity'] <= 0]
print(f'Negative or zero quantity transactions: {invalid_quant.shape[0]}')
print(invalid_quant[['Invoice', 'StockCode', 'Quantity']].head(2))
invalid_price = df[df['Price'] <= 0]
print(f'Negative or zero price transactions: {invalid_price.shape[0]}')
print(invalid_price[['Invoice', 'StockCode', 'Price']].head(2))
empty_desc = df[df['Description'].isnull() | (df['Description'].str.strip() == '')]
print(f'Records missing a product description: {empty_desc.shape[0]}')
print(empty_desc[['Invoice', 'StockCode', 'Description']].head(2))
df_nodup = df.drop_duplicates()
print(f'Records after removing duplicates: {df_nodup.shape[0]}')
invalid_customer = df[df['Customer ID'].isnull() | (df['Customer ID'] == 0)]
print(f'Rows missing or invalid Customer ID: {invalid_customer.shape[0]}')
print(invalid_customer[['Invoice', 'StockCode', 'Customer ID']].head(2))
future_dates = df[df['InvoiceDate'] > pd.Timestamp('2011-12-31')]
print(f'Transactions with future invoice dates: {future_dates.shape[0]}')
print(future_dates[['Invoice', 'InvoiceDate']].head(1))
Best Practices in Retail Data Cleaning#
- Always start by profiling missing and invalid data before any deeper sales or customer analysis.
- Flag, review, and document how you handle each type of data issue, keeping records auditable.
- Automate removal or fixing of negatives, blanks, and duplicates where possible.
- Prioritize crucial fields: dates, product info, customer IDs, and financial columns.
- Consistently re-check your cleaned data for hidden or indirect errors affecting business results.
np.random.seed(42)
n_orders = 1000
order_ids = list(range(1, n_orders+1))
customer_ids = np.random.randint(1000, 1500, n_orders)
product_ids = np.random.randint(1001, 1100, n_orders)
quantities = np.random.randint(-2, 5, n_orders)
order_dates = pd.date_range('2023-01-01', periods=n_orders, freq='h')
df_orders = pd.DataFrame({'OrderID': order_ids, 'CustomerID': customer_ids, 'ProductID': product_ids, 'Quantity': quantities, 'OrderDate': order_dates})
df_orders.loc[::50, 'Quantity'] = np.nan # insert some nulls
print(df_orders.head(5))
issues = df_orders[(df_orders['Quantity'].isnull()) | (df_orders['Quantity'] <= 0)]
print(f'Total problematic order records: {issues.shape[0]}')
print(issues.head(3))
df_clean = df_orders.dropna(subset=['Quantity'])
df_clean = df_clean[df_clean['Quantity'] > 0]
print(f'Remaining clean orders: {df_clean.shape[0]}')
End-to-End Example: Flag and Analyze Top-Selling Product#
- Now, we will identify and interpret the top-selling product by cleaned quantity from our simulated orders.
- This approach ensures that recommendations are based only on valid, trustworthy transactions.
- The outcome helps retailers focus stocking or marketing efforts on successful products and avoid out-of-stock issues.
top_product = df_clean.groupby('ProductID')['Quantity'].sum().idxmax()
top_sales = df_clean.groupby('ProductID')['Quantity'].sum().max()
print(f'Top-selling product is {top_product} with total quantity sold: {top_sales}')
Lesson Recap and Next Steps#
- Detecting and handling missing or invalid retail records is crucial to ensure data-driven business decisions are accurate and trusted.
- Cleaning your datasets before analysis prevents costly mistakes in sales, stock, or customer targeting.
- Practice these techniques regularly and automate your checks for large retail systems.
- Explore more advanced retail analytics skills in upcoming lessons to further strengthen your business value.
Found this useful?
All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.



