Mathew K Analytics

Lesson 9 · Market Research Analytics in Python

Introduction to Pandas for Market Research: Master Data Analysis with Python

Learn how Pandas helps analyze real market research datasets. Understand customer survey and behavioral data for better decisions. Produce insights that…

⬇ Download notebookOpen in Colab ↗

📓 Full notebook

Download .ipynb

Introduction to Pandas for Market Research#

  • Learn how Pandas helps analyze real market research datasets.
  • Understand customer survey and behavioral data for better decisions.
  • Produce insights that inform product, marketing, and service strategy.
  • These practical steps let you gain value from raw survey results.
import pandas as pd
import numpy as np
import openml
import warnings
warnings.filterwarnings('ignore')

Understanding Market Research Data and Common Pitfalls#

  • Market research data includes surveys, campaigns, and customer behaviors.
  • Columns may represent responses, demographics, and feedback.
  • Each row is a survey response, purchase event, or customer record.
  • Beginners may misinterpret missing values or mishandle categories.
  • Always check data types and understand what each field means.
dataset = openml.datasets.get_dataset(42178)
df, _, _, _ = dataset.get_data(dataset_format='dataframe')
print(df.shape)
print(df.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 1: Counting Churned Customers#

  • Business often wants to know how many customers are leaving.
  • We will count how many customers have churned based on survey data.
churn_counts = df['Churn'].value_counts()
print(churn_counts)
Churn
No     5174
Yes    1869
Name: count, dtype: int64

Beginner Example 2: Average Tenure of Customers#

  • Tenure tells how long customers stay with the company.
  • Finding the average can help spot trends in loyalty.
avg_tenure = df['tenure'].mean()
print('Average tenure (months):', round(avg_tenure,1))
Average tenure (months): 32.4

Beginner Example 3: Frequency of Each Contract Type#

  • See how many customers are on month-to-month, one year, or two year contracts.
  • This helps spot popular contract types in the survey.
contract_counts = df['Contract'].value_counts()
print(contract_counts)
Contract
Month-to-month    3875
Two year          1695
One year          1473
Name: count, dtype: int64
dataset = openml.datasets.get_dataset(1461)
df_marketing, _, _, _ = dataset.get_data(dataset_format='dataframe')
df_marketing.columns = ['age','job','marital','education','default','balance','housing','loan','contact','day','month','duration','campaign','pdays','previous','poutcome','response']
print(df_marketing.shape)
print(df_marketing.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  

Intermediate Example 1: Customer Response Rate#

  • Knowing the overall campaign response rate is a key marketing metric.
  • We will calculate the percent of customers who responded 'yes'.
total = len(df_marketing)
yes_count = (df_marketing['response'] == 'yes').sum()
response_rate = yes_count / total * 100
print(f'Response rate: {response_rate:.2f}%')
Response rate: 0.00%

Intermediate Example 2: Average Balance by Marital Status#

  • Segmenting by marital status can reveal spending behavior patterns.
  • We will break down average account balance for each status group.
avg_balance_by_marital = df_marketing.groupby('marital')['balance'].mean()
print(avg_balance_by_marital)
marital
divorced    1178.872287
married     1425.925590
single      1301.497654
Name: balance, dtype: float64

Intermediate Example 3: How Many Customers Have Loans?#

  • Loan information helps assess customer credit risk for new campaigns.
  • We will count customers who have at least one loan.
loan_holders = df_marketing[df_marketing['loan']=='yes'].shape[0]
print(f'Number of customers with loans: {loan_holders}')
Number of customers with loans: 7244
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  

Advanced Example 1: Highest Revenue Products#

  • Companies want to know which products drive the most revenue.
  • We will aggregate total sales by product and sort the top sellers.
df_retail['Revenue'] = df_retail['Quantity'] * df_retail['Price']
top_products = df_retail.groupby('Description')['Revenue'].sum().sort_values(ascending=False).head(5)
print(top_products)
Description
DOTCOM POSTAGE                        206245.48
REGENCY CAKESTAND 3 TIER              164762.19
WHITE HANGING HEART T-LIGHT HOLDER     99668.47
PARTY BUNTING                          98302.98
JUMBO BAG RED RETROSPOT                92356.03
Name: Revenue, dtype: float64

Advanced Example 2: Cohort Analysis of Customer Retention#

  • Cohort analysis tracks customer groups over time.
  • We will simulate simple monthly user activity to spot retention trends.
np.random.seed(0)
dates = pd.date_range('2021-01-01', periods=24, freq='M')
cohort_df = pd.DataFrame({'CustomerID': np.random.randint(1000,2000,len(dates)),
                          'Signup_Month': dates,
                          'Active_Users': np.random.randint(50,300,len(dates))})
print(cohort_df.head(3))
   CustomerID Signup_Month  Active_Users
0        1684   2021-01-31           138
1        1559   2021-02-28           131
2        1629   2021-03-31           215
import matplotlib.pyplot as plt
plt.plot(cohort_df['Signup_Month'], cohort_df['Active_Users'], marker='o')
plt.title('Customer Cohort Active Users Over Time')
plt.xlabel('Signup Month')
plt.ylabel('Active Users')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
No description has been provided for this image

Error Handling: Spotting Missing Survey Responses#

  • Missing values can bias results if you do not check for them.
  • Always count missing data before analysis.
print(df.isnull().sum())
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

Error Handling: Incorrect Grouping in Market Analysis#

  • A common mistake is grouping on the wrong field and misreading results.
  • Always triple-check your groupby before making business recommendations.
# Intentionally incorrect grouping (for teaching!)
bad_group = df.groupby('Partner')['MonthlyCharges'].mean()
print(bad_group)
Partner
No     61.945001
Yes    67.776264
Name: MonthlyCharges, dtype: float64

Error Handling: Misreading NPS and Likert Scale Data#

  • NPS and Likert scores must be interpreted using clear business rules.
  • 0 is not always the worst and 10 is not always the bestdefinitions matter.
np.random.seed(42)
nps_df = 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(nps_df.head(3))
   CustomerID  Age Region  NPS_Score
0           1   56   West          2
1           2   69  North          0
2           3   46   East          4
nps_df['Type'] = np.where(nps_df['NPS_Score'] >= 9, 'Promoter',
                       np.where(nps_df['NPS_Score'] <= 6, 'Detractor', 'Passive'))
print(nps_df['Type'].value_counts())
Type
Detractor    323
Passive       92
Promoter      85
Name: count, dtype: int64

Best Practices: Customer Segmentation Using Pandas#

  • Divide your customers into useful groups: by age, region, or spending.
  • Segmentation helps find target audiences for campaigns.
nps_df['AgeGroup'] = pd.cut(nps_df['Age'], bins=[17,29,49,69], labels=['Young','Middle','Senior'])
print(nps_df.groupby('AgeGroup')['NPS_Score'].mean())
AgeGroup
Young     4.887850
Middle    4.656085
Senior    5.107843
Name: NPS_Score, dtype: float64

Best Practices: Cross-Tabulation in Survey Results#

  • Cross-tabulation lets you compare two categorical variables, such as region and NPS type.
  • This reveals important relationships for marketing teams.
crosstab = pd.crosstab(nps_df['Region'], nps_df['Type'])
print(crosstab)
Type    Detractor  Passive  Promoter
Region                              
East           76       20        17
North          86       38        25
South          84       19        18
West           77       15        25

Best Practices: Score Construction for Survey Analytics#

  • Index scores help make survey data meaningful for business reports.
  • Let us create a 'Satisfaction Index' as a new metric.
nps_df['Satisfaction_Index'] = (nps_df['NPS_Score'] / 10) * 100
print(nps_df[['CustomerID','NPS_Score','Satisfaction_Index']].head(3))
   CustomerID  NPS_Score  Satisfaction_Index
0           1          2                20.0
1           2          0                 0.0
2           3          4                40.0

Best Practices: Trend Analysis on Market Data#

  • Spotting customer trends over time is vital for business direction.
  • Track how campaign responses change each month.
monthly_trend = df_marketing.groupby('month')['response'].value_counts().unstack().fillna(0)
print(monthly_trend.head())
response     1    2
month              
apr       2355  577
aug       5559  688
dec        114  100
feb       2208  441
jan       1261  142

End-to-End Market Research: From Survey to Insight#

  • We will take customer satisfaction survey data and summarize the main driver of churn.
  • The analysis will lead to a practical business recommendation.
churn_by_contract = df.groupby('Contract')['Churn'].value_counts(normalize=True).unstack().fillna(0) * 100
print(churn_by_contract)
Churn                  No        Yes
Contract                            
Month-to-month  57.290323  42.709677
One year        88.730482  11.269518
Two year        97.168142   2.831858
 

Found this useful?

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