Mathew K Analytics

Lesson 5 · Market Research Analytics in Python

Setting Up Python and Jupyter for Market Research Analytics

In this lesson, we will learn how to set up Python and Jupyter to analyze real market research and customer analytics data. We will focus on survey,…

⬇ 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

Setting Up Python and Jupyter for Market Research#

  • In this lesson, we will learn how to set up Python and Jupyter to analyze real market research and customer analytics data.
  • We will focus on survey, customer, and marketing datasets to solve business questions.
  • Knowing how to load, preview, and validate customer datasets is crucial for making evidence-based business decisions.
  • We will explore survey structure, customer lifecycle, segmentation, and campaign results.
  • You will produce actionable insights for product, marketing, or customer service teams.
  • Let us get started with practical hands-on steps.
import openml
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings('ignore')

Understanding Market Research Datasets#

  • Market research data captures opinions, behaviors, and demographics of customers or potential customers.
  • Data often comes from surveys (structured ratings, choices), transactions, or customer support logs.
  • Survey questions may use rating scales, NPS (Net Promoter Score), or open-ended text.
  • Beginner mistakes include misinterpreting response scales, ignoring missing data, and grouping incorrectly.
  • Always examine columns, response types, and missing values before analysis.
# Beginner Example 1: Load a customer satisfaction survey dataset
dataset = openml.datasets.get_dataset(42178)
df_satisfaction, _, _, _ = dataset.get_data(dataset_format='dataframe')
print(df_satisfaction.shape)
print(df_satisfaction.head(3))
(7043, 20)
   gender  SeniorCitizen Partner Dependents  tenure PhoneService  \
0  Female              0     Yes         No       1           No   
1    Male              0      No         No      34          Yes   
2    Male              0      No         No       2          Yes   

      MultipleLines InternetService OnlineSecurity OnlineBackup  \
0  No phone service             DSL             No          Yes   
1                No             DSL            Yes           No   
2                No             DSL            Yes          Yes   

  DeviceProtection TechSupport StreamingTV StreamingMovies        Contract  \
0               No          No          No              No  Month-to-month   
1              Yes          No          No              No        One year   
2               No          No          No              No  Month-to-month   

  PaperlessBilling     PaymentMethod  MonthlyCharges TotalCharges Churn  
0              Yes  Electronic check           29.85        29.85    No  
1               No      Mailed check           56.95       1889.5    No  
2              Yes      Mailed check           53.85       108.15   Yes  
# Beginner Example 2: Load marketing campaign performance data
dataset = openml.datasets.get_dataset(1461)
df_campaign, _, _, _ = dataset.get_data(dataset_format='dataframe')
df_campaign.columns = ['age','job','marital','education','default','balance','housing','loan','contact','day','month','duration','campaign','pdays','previous','poutcome','response']
print(df_campaign.shape)
print(df_campaign.head(3))
(45211, 17)
   age           job  marital  education default  balance housing loan  \
0   58    management  married   tertiary      no   2143.0     yes   no   
1   44    technician   single  secondary      no     29.0     yes   no   
2   33  entrepreneur  married  secondary      no      2.0     yes  yes   

   contact  day month  duration  campaign  pdays  previous poutcome response  
0  unknown    5   may     261.0         1   -1.0       0.0  unknown        1  
1  unknown    5   may     151.0         1   -1.0       0.0  unknown        1  
2  unknown    5   may      76.0         1   -1.0       0.0  unknown        1  
# Beginner Example 3: Load open-ended customer feedback
df_feedback = pd.DataFrame({'CustomerID':[1,2,3,4,5], 'Feedback':['Great service and friendly staff','Delivery was slow and packaging was poor','Excellent quality, will buy again','Customer support needs improvement','Good value for money']})
print(df_feedback.shape)
print(df_feedback.head(3))
(5, 2)
   CustomerID                                  Feedback
0           1          Great service and friendly staff
1           2  Delivery was slow and packaging was poor
2           3         Excellent quality, will buy again
# Beginner Example 4: Load Net Promoter Score (NPS) survey data (synthetic)
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)})
print(df_nps.shape)
print(df_nps.head(3))
(500, 4)
   CustomerID  Age Region  NPS_Score
0           1   56   West          2
1           2   69  North          0
2           3   46   East          4
# Beginner Example 5: Load online retail transaction data (public UCI data)
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))
(541910, 8)
  Invoice StockCode                         Description  Quantity  \
0  536365    85123A  WHITE HANGING HEART T-LIGHT HOLDER         6   
1  536365     71053                 WHITE METAL LANTERN         6   
2  536365    84406B      CREAM CUPID HEARTS COAT HANGER         8   

          InvoiceDate  Price  Customer ID         Country  
0 2010-12-01 08:26:00   2.55      17850.0  United Kingdom  
1 2010-12-01 08:26:00   3.39      17850.0  United Kingdom  
2 2010-12-01 08:26:00   2.75      17850.0  United Kingdom  
# Intermediate Example 1: Check for missing survey responses in the satisfaction dataset
missing_counts = df_satisfaction.isnull().sum()
print(missing_counts)
gender              0
SeniorCitizen       0
Partner             0
Dependents          0
tenure              0
PhoneService        0
MultipleLines       0
InternetService     0
OnlineSecurity      0
OnlineBackup        0
DeviceProtection    0
TechSupport         0
StreamingTV         0
StreamingMovies     0
Contract            0
PaperlessBilling    0
PaymentMethod       0
MonthlyCharges      0
TotalCharges        0
Churn               0
dtype: int64
# Intermediate Example 2: Explore value counts in key categorical variables
print(df_satisfaction['gender'].value_counts())
print(df_satisfaction['Contract'].value_counts())
gender
Male      3555
Female    3488
Name: count, dtype: int64
Contract
Month-to-month    3875
Two year          1695
One year          1473
Name: count, dtype: int64
# Intermediate Example 3: Calculate churn rate from satisfaction dataset
churn_rate = df_satisfaction['Churn'].value_counts(normalize=True)
print('Churn Rate by Category:')
print(churn_rate)
Churn Rate by Category:
Churn
No     0.73463
Yes    0.26537
Name: proportion, dtype: float64
# Intermediate Example 4: Average NPS score and regional differences
avg_nps = df_nps.groupby('Region')['NPS_Score'].mean()
print('Average NPS Score by Region:')
print(avg_nps)
Average NPS Score by Region:
Region
East     4.504425
North    5.214765
South    4.719008
West     5.025641
Name: NPS_Score, dtype: float64
# Intermediate Example 5: Convert NPS scores to promoter, passive, detractor categories
def nps_category(score):
    if score >= 9:
        return 'Promoter'
    elif score >= 7:
        return 'Passive'
    else:
        return 'Detractor'
df_nps['Category'] = df_nps['NPS_Score'].apply(nps_category)
print(df_nps['Category'].value_counts())
Category
Detractor    323
Passive       92
Promoter      85
Name: count, dtype: int64
# Intermediate Example 6: Quick keyword extraction demo on feedback text
all_feedback = ' '.join(df_feedback['Feedback'])
keywords = pd.Series(all_feedback.lower().replace(',','').replace('.','').split()).value_counts().head(5)
print('Top keywords in feedback:')
print(keywords)
Top keywords in feedback:
and         2
was         2
great       1
service     1
friendly    1
Name: count, dtype: int64
# Advanced Example 1: Automated missing value imputation for satisfaction survey
df_satisfaction_filled = df_satisfaction.copy()
for col in df_satisfaction_filled.columns:
    if df_satisfaction_filled[col].dtype == 'O':
        df_satisfaction_filled[col].fillna(df_satisfaction_filled[col].mode()[0], inplace=True)
    else:
        df_satisfaction_filled[col].fillna(df_satisfaction_filled[col].median(), inplace=True)
print('Remaining missing values:')
print(df_satisfaction_filled.isnull().sum().sum())
Remaining missing values:
0
# Advanced Example 2: Cross-tabulation of contract type vs churn outcome
crosstab = pd.crosstab(df_satisfaction['Contract'], df_satisfaction['Churn'], normalize='index')
print('Churn rate by contract type:')
print(crosstab)
Churn rate by contract type:
Churn                 No       Yes
Contract                          
Month-to-month  0.572903  0.427097
One year        0.887305  0.112695
Two year        0.971681  0.028319
# Advanced Example 3: Construct a monthly cohort for online retail customers
df_retail['Signup_Month'] = df_retail['InvoiceDate'].dt.to_period('M')
cohort_counts = df_retail.groupby('Signup_Month')['Customer ID'].nunique()
print('Number of unique customers by month:')
print(cohort_counts.head(6))
Number of unique customers by month:
Signup_Month
2010-12     948
2011-01     783
2011-02     798
2011-03    1020
2011-04     899
2011-05    1079
Freq: M, Name: Customer ID, dtype: int64
# Advanced Example 4: Segment campaign audience by response
segment_counts = df_campaign.groupby('response')['age'].count()
print('Number of responses to campaign:')
print(segment_counts)
Number of responses to campaign:
response
1    39922
2     5289
Name: age, dtype: int64
# Advanced Example 5: Construct a composite satisfaction score from multiple indicators
df_satisfaction['SatisfactionScore'] = (df_satisfaction['MonthlyCharges']*0.3 + df_satisfaction['tenure']*0.5 - df_satisfaction['SeniorCitizen']*10)
print(df_satisfaction[['MonthlyCharges','tenure','SeniorCitizen','SatisfactionScore']].head(5))
   MonthlyCharges  tenure  SeniorCitizen  SatisfactionScore
0           29.85       1              0              9.455
1           56.95      34              0             34.085
2           53.85       2              0             17.155
3           42.30      45              0             35.190
4           70.70       2              0             22.210
# Error Handling 1: What if column names are misspelled?
try:
    print(df_satisfaction['Gendre'].value_counts())
except KeyError as e:
    print('Error:', str(e), '-- Did you mean gender?')
Error: 'Gendre' -- Did you mean gender?
# Error Handling 2: Handling missing values when grouping
try:
    churn_group = df_satisfaction.groupby('Contract')['Churn'].mean()
    print(churn_group)
except Exception as e:
    print('Error in groupby calculation:', e)
Error in groupby calculation: agg function failed [how->mean,dtype->object]
# Error Handling 3: Detect likely scale interpretation mistakes in NPS
if df_nps['NPS_Score'].max() > 10 or df_nps['NPS_Score'].min() < 0:
    print('Warning: NPS Scores should be between 0 and 10! Possible scale alignment issue.')
else:
    print('NPS score range is valid.')
NPS score range is valid.

Best Practices for Market Research Analytics#

  • Segment your data by meaningful groups (age, region, contract).
  • Use cross-tabulation to compare satisfaction, churn, or responses across segments.
  • Construct indices and composite scores when you need a single performance metric.
  • Analyze trend data over time with cohort or time series methods.
  • Carefully check for missing data and misinterpretation before presenting insights.
# Best Practice Example: Age segmentation on churn
bins = [17, 30, 40, 50, 60, 100]
labels = ['18-29','30-39','40-49','50-59','60+']
df_satisfaction['AgeGroup'] = pd.cut(df_satisfaction['SeniorCitizen']*60 + 30, bins, labels=labels)
print(df_satisfaction.groupby('AgeGroup')['Churn'].value_counts(normalize=True))
AgeGroup  Churn
18-29     No       0.763938
          Yes      0.236062
30-39     No       0.000000
          Yes      0.000000
40-49     No       0.000000
          Yes      0.000000
50-59     No       0.000000
          Yes      0.000000
60+       No       0.583187
          Yes      0.416813
Name: proportion, dtype: float64

End-to-End Problem: From Data to Insight#

  • Let us answer: What is driving customer churn in our satisfaction survey?
  • We will group by contract type and calculate average monthly charges for churned vs non-churned customers.
  • We will recommend action based on where churn and charges are both high.
  • This is a typical journey from data to actionable recommendation.
# End-to-End Step 1: Calculate churn and average charges by contract type
results = df_satisfaction.groupby(['Contract','Churn'])['MonthlyCharges'].mean().unstack()
print('Average Monthly Charges by Churn and Contract Type:')
print(results)
Average Monthly Charges by Churn and Contract Type:
Churn                  No        Yes
Contract                            
Month-to-month  61.462635  73.019396
One year        62.508148  85.050904
Two year        60.012477  86.777083
# End-to-End Step 2: Write a summary insight to a text file
with open('churn_insight.txt', 'w') as f:
    f.write('Customers with monthly contracts and high monthly charges have the highest churn risk. We recommend new incentives or personalized offers for this group.')

Congratulations! You have set up Python for Market Research Analytics#

  • You have learned to load real public datasets, handle missing data, segment audiences, and extract actionable business insights.
  • Try adapting these techniques to your own company or case study.
  • For more hands-on tutorials, search for 'Python market research Jupyter' on YouTube!

Found this useful?

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