Lesson 16 · Market Research Analytics in Python
How to Identify Missing and Invalid Survey Responses in Python | Market Research Analytics
This lesson shows you how to find missing or invalid responses in real customer or market survey data. Clean survey data is crucial for insight accuracy and…
- CourseMarket Research Analytics in Python
- Lesson16 of 56
- Video20 min
- FormatJupyter notebook · 17 code cells
What you'll learn
- Understanding Survey Data Sources and Layout
- Beginner Example 1: Loading Customer Satisfaction Survey Data
- Beginner Example 2: Checking for Missing Responses in the Survey
- Beginner Example 3: Visualizing Missingness
- Intermediate Example 1: Finding Invalid Categorical Responses
- Intermediate Example 2: Detecting Out-of-Range Numerical Answers
- Intermediate Example 3: Checking Missingness by Customer Segment
- Advanced Example 1: Loading a Synthetic NPS Survey with Programmed Missing Values
Data
No separate download needed — the notebook creates or downloads everything it uses.
📓 Full notebook
Download .ipynbIdentifying Missing and Invalid Survey Responses#
- This lesson shows you how to find missing or invalid responses in real customer or market survey data.
- Clean survey data is crucial for insight accuracy and business decisions.
- You will learn how to check for missing values, spot input errors, and interpret their impact on survey results.
- By the end, you will be able to isolate problematic survey entries and explain their effect on marketing strategy.
import warnings
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import openml
warnings.filterwarnings('ignore')
Understanding Survey Data Sources and Layout#
- Surveys capture customer demographics, ratings, and open-ended feedback.
- A row is usually one respondent; columns are questions or observed traits.
- Mistakes beginners make:
- Ignoring missing values (they bias averages and group summaries).
- Not validating if responses are within expected ranges.
- Misreading text data, like misclassifying blanks as valid answers.
Beginner Example 1: Loading Customer Satisfaction Survey Data#
- We use a real customer satisfaction survey from OpenML.
- First, inspect the data for completeness.
dataset = openml.datasets.get_dataset(42178)
df, _, _, _ = dataset.get_data(dataset_format='dataframe')
print(df.shape)
print(df.head(3))
Beginner Example 2: Checking for Missing Responses in the Survey#
- Sometimes survey respondents leave answers blank.
- We will identify where information is missing.
missing_count = df.isnull().sum()
print(missing_count.sort_values(ascending=False))
Beginner Example 3: Visualizing Missingness#
- Seeing where missing responses cluster helps find problematic questions.
- We will create a simple bar plot of missing values per column.
# Check and visualize missing values safely
missing = df.isnull().sum().sort_values(ascending=False)
missing_nonzero = missing[missing > 0]
if len(missing_nonzero) > 0:
plt.figure(figsize=(10,4))
missing_nonzero.plot(kind='bar', color='salmon')
plt.title('Missing Value Count by Column')
plt.xlabel('Column')
plt.ylabel('Count')
plt.show()
else:
print('No missing values found in the dataset.')
Intermediate Example 1: Finding Invalid Categorical Responses#
- Some survey questions have allowed answer options (e.g., Male/Female).
- We check if any responses fall outside of these allowed categories.
allowed_genders = ['Male', 'Female']
invalid_gender = ~df['gender'].isin(allowed_genders)
print('Invalid gender responses:', df[invalid_gender]['gender'].unique())
Intermediate Example 2: Detecting Out-of-Range Numerical Answers#
- Survey scales often ask respondents to give rates in a certain range (e.g., 1-5).
- Mistakes or data entry errors may create responses outside this range.
invalid_tenure = (df['tenure'] < 0) | (df['tenure'] > 72)
print('Number of invalid tenure entries:', invalid_tenure.sum())
print('Example invalid tenure values:', df.loc[invalid_tenure, 'tenure'].unique())
Intermediate Example 3: Checking Missingness by Customer Segment#
- Missing responses are often more common in certain demographic groups.
- Segmenting missingness reveals hidden survey bias.
seg_missing = df.groupby('SeniorCitizen')['TotalCharges'].apply(lambda x: x.isnull().mean())
print(seg_missing)
Advanced Example 1: Loading a Synthetic NPS Survey with Programmed Missing Values#
- We create a synthetic Net Promoter Score (NPS) survey with known missing values.
- This helps us test missingness detection and repair tools.
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)})
# Intentionally set 10% of NPS_Score as missing
idx = np.random.choice(nps_df.index, size=50, replace=False)
nps_df.loc[idx, 'NPS_Score'] = np.nan
print(nps_df.head())
Advanced Example 2: Quantifying Impact of Missingness on Customer Metrics#
- How do missing survey responses change your business conclusions?
- We compare average NPS before and after dropping incomplete responses.
avg_with_missing = nps_df['NPS_Score'].mean()
avg_no_missing = nps_df['NPS_Score'].dropna().mean()
print(f'Average NPS (with missing as NaN): {avg_with_missing:.2f}')
print(f'Average NPS (excluding missing): {avg_no_missing:.2f}')
Advanced Example 3: Identifying and Handling Impossible Values in NPS#
- NPS scores must be in range 0 to 10, inclusive.
- We simulate and catch any impossible scores.
nps_df.loc[5,'NPS_Score'] = 15 # Simulate invalid score
invalid_idx = (nps_df['NPS_Score'] < 0) | (nps_df['NPS_Score'] > 10)
print('Indexes of impossible NPS scores:', nps_df[invalid_idx].index.tolist())
nps_df.loc[invalid_idx, 'NPS_Score'] = np.nan
print('Impossible values replaced with NaN.')
Error Handling Example: Common Mistakes with Missing Data#
- Not all missing values are marked as NaN - sometimes blanks or special codes are used.
- We will search for common representations of missing data beyond just NaN.
custom_missing = nps_df['Region'].isin(['', 'NA', 'Unknown', None])
print('Number of non-standard missing Region entries:', custom_missing.sum())
Error Handling Example: Incorrect Grouping When Summarizing Survey Data#
- A common analytics mistake is grouping by a column with too many missing values.
- We will see how dropping missing groups changes the group average.
grouped = nps_df.groupby('Region')['NPS_Score'].mean()
print(grouped)
grouped_dropna = nps_df.dropna(subset=['Region']).groupby('Region')['NPS_Score'].mean()
print('Grouped means after dropping missing:', grouped_dropna)
Error Handling Example: Misreading Likert Scale or NPS Values#
- Sometimes, analysts forget that 0 on an NPS or Likert scale is valid (not missing or 'bad').
- We examine a summary to check if zeros are present and treated properly.
print('NPS value counts (including 0):')
print(nps_df['NPS_Score'].value_counts(dropna=False).sort_index())
Best Practices: Survey Data Segmentation and Cross-Tab Analysis#
- Segmenting respondents helps spot missingness patterns and improve survey targeting.
- Cross-tabulation of missing data can uncover which groups tend to skip questions.
- Let us analyze missing NPS by age group and region.
nps_df['AgeGroup'] = pd.cut(nps_df['Age'], bins=[17,30,40,50,60,80], labels=['18-30','31-40','41-50','51-60','61+'])
missing_xtab = pd.crosstab(nps_df['AgeGroup'], nps_df['Region'], values=nps_df['NPS_Score'].isnull(), aggfunc='sum', dropna=False)
print(missing_xtab)
Best Practices: Constructing Missingness Indices and Reporting Trends#
- Track the proportion of missing answers over time, region, or cohort.
- A rising trend could reveal survey fatigue or disengaged segments.
# Simulate a survey timestamp column
nps_df['ResponseMonth'] = pd.to_datetime('2022-01-01') + pd.to_timedelta(np.random.randint(0,180, len(nps_df)), unit='D')
nps_df['Month'] = nps_df['ResponseMonth'].dt.to_period('M')
monthly_missing = nps_df.groupby('Month')['NPS_Score'].apply(lambda x: x.isnull().mean())
monthly_missing.plot(marker='o')
plt.ylabel('Fraction Missing')
plt.title('Monthly Survey NPS Missingness')
plt.show()
End-to-End Example: Flagging and Reporting on a Real Survey's Data Quality#
- We will summarize missing or invalid NPS responses by customer region.
- The final table makes it easy for executives to spot data issues by group.
report = nps_df.groupby('Region').agg(
responses=('NPS_Score', 'count'),
missing_count=('NPS_Score', lambda x: x.isnull().sum()),
invalid_count=('NPS_Score', lambda x: ((x<0)|(x>10)).sum())
)
report['missing_pct'] = (report['missing_count'] / (report['responses'] + report['missing_count'])) * 100
print(report.sort_values('missing_pct', ascending=False))
Found this useful?
All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.



