Lesson 46 · Market Research Analytics in Python
Introduction to Trend Analysis in Market Research
In this lesson, we will learn how to analyze and visualize trends in real-world customer and market research data. Understanding trends helps businesses…
- CourseMarket Research Analytics in Python
- Lesson46 of 56
- Video21 min
- FormatJupyter notebook · 19 code cells
What you'll learn
Data
No separate download needed — the notebook creates or downloads everything it uses.
📓 Full notebook
Download .ipynbIntroduction to Trend Analysis in Market Research#
- In this lesson, we will learn how to analyze and visualize trends in real-world customer and market research data.
- Understanding trends helps businesses identify emerging needs, opportunities, and potential problems.
- By the end, you will be able to extract, plot, and interpret trends from key market research datasets, and translate these trends into actionable business insights.
- This knowledge is essential for making informed decisions and staying competitive in your field.
import warnings
warnings.filterwarnings('ignore')
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import openml
Core Concepts: What is Trend Analysis in Market Research?#
- Market research datasets may contain customer demographics, sales records, survey responses, or feedback over time.
- Trends help us understand how customer attitudes, satisfaction, or behaviors change, revealing patterns, seasonality, or shifts in perception.
- Responses are usually structured as numbers (like satisfaction scores), choices (like NPS or churn), or text (feedback).
- Beginners often misinterpret time-based data by ignoring units, missing missing values, or using the wrong aggregation level (daily vs monthly).
- Accurate trend analysis depends on using dates/times correctly and understanding what each column means.
# Load customer satisfaction survey data from OpenML
dataset = openml.datasets.get_dataset(42178)
df_cs, _, _, _ = dataset.get_data(dataset_format='dataframe')
print(df_cs.shape)
print(df_cs.head(3))
# Check for missing values in key trend columns
missing = df_cs[['tenure', 'MonthlyCharges', 'Churn']].isnull().sum()
print(missing)
# Beginner trend: Average monthly charges by customer tenure
df_cs_grouped = df_cs.groupby('tenure')['MonthlyCharges'].mean().reset_index()
plt.plot(df_cs_grouped['tenure'], df_cs_grouped['MonthlyCharges'])
plt.xlabel('Tenure (months)')
plt.ylabel('Average Monthly Charges')
plt.title('Trend: Avg Monthly Charges vs. Tenure')
plt.show()
# Load online retail behavior data (real transactions)
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/00502/online_retail_II.xlsx'
df_retail = pd.read_excel(url, sheet_name='Year 2010-2011')
df_retail['InvoiceDate'] = pd.to_datetime(df_retail['InvoiceDate'])
print(df_retail.shape)
print(df_retail.head(3))
# Beginner trend: Number of transactions per month
df_retail['Month'] = df_retail['InvoiceDate'].dt.to_period('M')
monthly_counts = df_retail.groupby('Month').size()
monthly_counts.plot(kind='line', marker='o')
plt.xlabel('Month')
plt.ylabel('Number of Transactions')
plt.title('Number of Transactions per Month')
plt.show()
# Intermediate: Trend of total sales value per month
df_retail['TotalSales'] = df_retail['Quantity'] * df_retail['Price']
monthly_sales = df_retail.groupby('Month')['TotalSales'].sum()
monthly_sales.plot(kind='bar', color='skyblue')
plt.ylabel('Total Sales Value')
plt.title('Total Sales Value per Month')
plt.xticks(rotation=45)
plt.show()
# Load marketing campaign performance data
dataset = openml.datasets.get_dataset(1461)
df_mkt, _, _, _ = dataset.get_data(dataset_format='dataframe')
df_mkt.columns = ['age','job','marital','education','default','balance','housing','loan','contact','day','month','duration','campaign','pdays','previous','poutcome','response']
print(df_mkt.shape)
print(df_mkt.head(3))
# Intermediate trend: Campaign response rates by month
response_by_month = df_mkt.groupby('month')['response'].value_counts().unstack().fillna(0)
response_by_month['response_rate'] = response_by_month['2'] / (response_by_month['2'] + response_by_month['1'])
response_by_month['response_rate'].plot(kind='bar', color='green')
plt.ylabel('Response Rate')
plt.xlabel('Campaign Month')
plt.title('Marketing Campaign Response Rates by Month')
plt.show()
# Intermediate: Trend of average customer satisfaction by churn status
satisfaction_churn = df_cs.groupby('Churn')['MonthlyCharges'].mean()
satisfaction_churn.plot(kind='bar', color=['orange','gray'])
plt.ylabel('Average Monthly Charges')
plt.title('Avg Monthly Charges: Churned vs. Retained Customers')
plt.xticks(rotation=0)
plt.show()
# Advanced: Calculate rolling trend of transactions (moving average)
transactions_daily = df_retail.resample('D', on='InvoiceDate').size()
rolling_tx = transactions_daily.rolling(window=14, min_periods=1).mean()
plt.plot(rolling_tx)
plt.xlabel('Date')
plt.ylabel('14-day Moving Avg: Transactions')
plt.title('Smoothed Trend of Daily Transactions')
plt.show()
# Advanced: Segment trend analysis by country
countries = ['United Kingdom', 'Germany', 'France', 'Netherlands']
for country in countries:
sales = df_retail[df_retail['Country'] == country].groupby('Month')['TotalSales'].sum()
plt.plot(sales.index.astype(str), sales, label=country)
plt.legend()
plt.xlabel('Month')
plt.ylabel('Total Sales Value')
plt.title('Monthly Sales Trend by Country')
plt.xticks(rotation=45)
plt.show()
# Error example: What happens with missing values in grouping?
df_missing = df_cs.copy()
df_missing.loc[0:5, 'MonthlyCharges'] = np.nan
grouped = df_missing.groupby('tenure')['MonthlyCharges'].mean()
print(grouped.head(10))
# Debug: Identifying missing and correcting with imputation
imputed = df_missing['MonthlyCharges'].fillna(df_missing['MonthlyCharges'].mean())
print('Original mean:', df_missing['MonthlyCharges'].mean())
print('Imputed mean:', imputed.mean())
# Error: Misinterpreting NPS scaleload and plot synthetic NPS data
np.random.seed(42)
df_nps = pd.DataFrame({'CustomerID': range(1,501),
'Age': np.random.randint(18,70,500),
'Region': np.random.choice(['North','South','East','West'],500),
'NPS_Score': np.random.randint(0,11,500)})
df_nps['Month'] = np.random.choice(list(range(1, 13)), size=500)
monthly_nps = df_nps.groupby('Month')['NPS_Score'].mean()
plt.plot(monthly_nps.index, monthly_nps.values, marker='o', linestyle='-')
plt.xlabel('Month')
plt.ylabel('Avg NPS Score')
plt.title('Average NPS Score by Month')
plt.show()
Best Practices: How to Analyze Trends for Market Research#
- Segment your analysis by customer type, location, or time period for deeper insights.
- Cross-tabulation lets you see how trends differ between groupslike churned vs. loyal customers.
- Use rolling averages to smooth out noisy data and highlight true patterns.
- Build composite indexes (like satisfaction or loyalty scores) from multiple variables rather than one measure.
- Communicate findings using clear charts and business language, not just statistics.
# Best practice demo: Cross-tab trend by customer contract type
df_cs_contract = df_cs.groupby(['tenure','Contract'])['MonthlyCharges'].mean().unstack()
df_cs_contract.plot(figsize=(8,5))
plt.xlabel('Tenure (months)')
plt.ylabel('Average Monthly Charges')
plt.title('Trend: Monthly Charges by Contract Type Over Tenure')
plt.show()
# Pattern: Construct a composite satisfaction index
df_cs['SatIndex'] = (
df_cs['OnlineSecurity'].map({'No': 0, 'Yes': 1}) +
df_cs['OnlineBackup'].map({'No': 0, 'Yes': 1}) +
df_cs['TechSupport'].map({'No': 0, 'Yes': 1})
) / 3
monthly_sat = df_cs.groupby('tenure')['SatIndex'].mean()
plt.plot(monthly_sat.index, monthly_sat.values)
plt.xlabel('Tenure (months)')
plt.ylabel('Satisfaction Index (0-1)')
plt.title('Composite Satisfaction Index by Tenure')
plt.show()
# End-to-end: Find evidence for customer churn risk over time
df_cs_trend = df_cs.groupby('tenure')['Churn'].value_counts(normalize=True).unstack().fillna(0)
plt.plot(df_cs_trend.index, df_cs_trend['Yes'], label='Churned')
plt.plot(df_cs_trend.index, df_cs_trend['No'], label='Retained')
plt.xlabel('Tenure (months)')
plt.ylabel('Fraction of Customers')
plt.title('Customer Churn vs. Tenure Trend')
plt.legend()
plt.show()
churn_tipping_point = df_cs_trend['Yes'].idxmax()
print(f'Business insight: Churn risk peaks at {churn_tipping_point} months tenure.')
Found this useful?
All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.



