Activity_Hypothesis testing with Python
November 27, 2025
1 Activity: Hypothesis testing with Python
1.1 Introduction
As you’ve been learning, analysis of variance (commonly called ANOVA) is a group of statistical
techniques that test the difference of means among three or more groups. It’s a powerful tool for
determining whether population means are different across groups and for answering a wide range
of business questions.
In this activity, you are a data professional working with historical marketing promotion data.
You will use the data to run a one-way ANOVA and a post hoc ANOVA test. Then, you will
communicate your results to stakeholders. These experiences will help you make more confident
recommendations in a professional setting.
In your dataset, each row corresponds to an independent marketing promotion, where your business
uses TV, social media, radio, and influencer promotions to increase sales. You have previously
provided insights about how different promotion types affect sales; now stakeholders want to know
if sales are significantly different among various TV and influencer promotion types.
To address this request, a one-way ANOVA test will enable you to determine if there is a statistically
significant difference in sales among groups. This includes: * Using plots and descriptive statistics
to select a categorical independent variable * Creating and fitting a linear regression model with
the selected categorical independent variable * Checking model assumptions * Performing and
interpreting a one-way ANOVA test * Comparing pairs of groups using an ANOVA post hoc test
* Interpreting model outputs and communicating the results to nontechnical stakeholders
1.2 Step 1: Imports
[12]: # Import libraries and packages.
import pandas as pd
import [Link] as plt
import seaborn as sns
import [Link] as sm
from [Link] import ols
from [Link] import pairwise_tukeyhsd
Pandas was used to load the dataset marketing_sales_data.csv as data, now display the first five
rows. The variables in the dataset have been adjusted to suit the objectives of this lab. As shown
1
in this cell, the dataset has been automatically loaded in for you. You do not need to download
the .csv file, or provide more code, in order to access the dataset and proceed with this lab. Please
continue with this activity by completing the following instructions.
[13]: # RUN THIS CELL TO IMPORT YOUR DATA.
data = pd.read_csv('marketing_sales_data.csv')
# Display the first five rows.
[Link]()
[13]: TV Radio Social Media Influencer Sales
0 Low 1.218354 1.270444 Micro 90.054222
1 Medium 14.949791 0.274451 Macro 222.741668
2 Low 10.377258 0.061984 Mega 102.774790
3 High 26.469274 7.070945 Micro 328.239378
4 High 36.876302 7.618605 Mega 351.807328
The features in the data are: * TV promotion budget (in Low, Medium, and High categories)
* Social media promotion budget (in millions of dollars) * Radio promotion budget (in millions
of dollars) * Sales (in millions of dollars) * Influencer size (in Mega, Macro, Nano, and Micro
categories)
Question: Why is it useful to perform exploratory data analysis before constructing a linear
regression model?
EDA is helpful in following ways: 1. To understand the structure, size and shape of data 2. To
clean the data 3. To get insightful results
1.3 Step 2: Data exploration
First, use a boxplot to determine how Sales vary based on the TV promotion budget category.
[14]: # Create a boxplot with TV and Sales.
[Link](figsize=(8,4))
[Link](x = data['TV'], y = data['Sales'])
[Link]('Sales vary based on TV promotion budget')
[Link]()
2
Question: Is there variation in Sales based off the TV promotion budget?
Yes there’s a variation, high budget shows high sales and low budget sales less sales
Now, use a boxplot to determine how Sales vary based on the Influencer size category.
[16]: # Create a boxplot with Influencer and Sales.
[Link](x= data['Influencer'], y= data['Sales'])
[Link]('Sales vary based on the Influencer size')
[Link]()
3
Question: Is there variation in Sales based off the Influencer size?
There is some variation in Sales across the Influencer groups, but it may not be significant.
1.3.1 Remove missing data
You may recall from prior labs that this dataset contains rows with missing values. To correct this,
drop these rows. Then, confirm the data contains no missing values.
[17]: # Drop rows that contain missing data and update the DataFrame.
data = [Link](axis=0)
# Confirm the data contains no missing values.
[Link]().sum()
[17]: TV 0
Radio 0
Social Media 0
Influencer 0
Sales 0
dtype: int64
4
1.4 Step 3: Model building
Fit a linear regression model that predicts Sales using one of the independent categorical variables
in data. Refer to your previous code for defining and fitting a linear regression model.
[20]: # Define the OLS formula.
ols_formula = 'Sales ~ C(TV)'
# Create an OLS model.
OLS = ols(formula = ols_formula, data = data)
# Fit the model.
model = [Link]()
# Save the results summary.
result = [Link]()
# Display the model results.
result
[20]: <class '[Link]'>
"""
OLS Regression Results
==============================================================================
Dep. Variable: Sales R-squared: 0.874
Model: OLS Adj. R-squared: 0.874
Method: Least Squares F-statistic: 1971.
Date: Thu, 27 Nov 2025 Prob (F-statistic): 8.81e-256
Time: 12:13:01 Log-Likelihood: -2778.9
No. Observations: 569 AIC: 5564.
Df Residuals: 566 BIC: 5577.
Df Model: 2
Covariance Type: nonrobust
================================================================================
===
coef std err t P>|t| [0.025
0.975]
--------------------------------------------------------------------------------
---
Intercept 300.5296 2.417 124.360 0.000 295.783
305.276
C(TV)[[Link]] -208.8133 3.329 -62.720 0.000 -215.353
-202.274
C(TV)[[Link]] -101.5061 3.325 -30.526 0.000 -108.038
-94.975
==============================================================================
Omnibus: 450.714 Durbin-Watson: 2.002
5
Prob(Omnibus): 0.000 Jarque-Bera (JB): 35.763
Skew: -0.044 Prob(JB): 1.71e-08
Kurtosis: 1.775 Cond. No. 3.86
==============================================================================
Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly
specified.
"""
Question: Which categorical variable did you choose for the model? Why?
• TV was selected as the preceding analysis showed a strong relationship between the TV
promotion budget and the average Sales.
• Influencer was not selected because it did not show a strong relationship to Sales in the
analysis.
1.4.1 Check model assumptions
Now, check the four linear regression assumptions are upheld for your model.
Question: Is the linearity assumption met?
Because the model does not have any continuous independent variables, the linearity assumption
is not required.
The independent observation assumption states that each observation in the dataset is independent.
As each marketing promotion (row) is independent from one another, the independence assumption
is not violated.
Next, verify that the normality assumption is upheld for the model.
[22]: # Calculate the residuals.
residuals = [Link]
# setup two plots in one frame
fig, axes = [Link](1,2, figsize = (8,4))
# Create a histogram with the residuals.
[Link](residuals, ax = axes[0])
axes[0].set_title('Histogram of Residuals')
axes[0].set_xlabel('Residuals')
# Create a QQ plot of the residuals.
[Link](residuals, line = 's', ax = axes[1])
axes[1].set_title('Q-Q Plot of residuals')
# Use matplotlib's tight_layout() function to add space between plots for a␣
,→cleaner appearance.
6
plt.tight_layout()
# Show the plots
[Link]()
Question: Is the normality assumption met?
There is reasonable concern that the normality assumption is not met when TV is used as the
independent variable predicting Sales. The normal q-q forms an ‘S’ that deviates off the red
diagonal line, which is not desired behavior
Now, verify the constant variance (homoscedasticity) assumption is met for this model.
[24]: # Create a scatter plot with the fitted values from the model and the residuals.
# 1. Calculate fitted values:
fitted_values = [Link]
# 2. Now create scatter plot
fig = [Link](x = fitted_values, y = residuals)
# 3. Set x label
fig.set_xlabel('Fitted Values')
# 4. Set y label
fig.set_ylabel('Residuals')
# 5. Set title
fig.set_title('Fitted Values VS Residuals')
7
# Add a line at y = 0 to visualize the variance of residuals above and below 0.
[Link](0)
# Show the plot
[Link]()
Question: Is the constant variance (homoscedasticity) assumption met?
The variance where there are fitted values is similarly distributed, validating that the constant
variance assumption is met.
1.5 Step 4: Results and evaluation
First, display the OLS regression results.
[25]: # Display the model results summary.
result
[25]: <class '[Link]'>
"""
OLS Regression Results
==============================================================================
8
Dep. Variable: Sales R-squared: 0.874
Model: OLS Adj. R-squared: 0.874
Method: Least Squares F-statistic: 1971.
Date: Thu, 27 Nov 2025 Prob (F-statistic): 8.81e-256
Time: 12:13:01 Log-Likelihood: -2778.9
No. Observations: 569 AIC: 5564.
Df Residuals: 566 BIC: 5577.
Df Model: 2
Covariance Type: nonrobust
================================================================================
===
coef std err t P>|t| [0.025
0.975]
--------------------------------------------------------------------------------
---
Intercept 300.5296 2.417 124.360 0.000 295.783
305.276
C(TV)[[Link]] -208.8133 3.329 -62.720 0.000 -215.353
-202.274
C(TV)[[Link]] -101.5061 3.325 -30.526 0.000 -108.038
-94.975
==============================================================================
Omnibus: 450.714 Durbin-Watson: 2.002
Prob(Omnibus): 0.000 Jarque-Bera (JB): 35.763
Skew: -0.044 Prob(JB): 1.71e-08
Kurtosis: 1.775 Cond. No. 3.86
==============================================================================
Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly
specified.
"""
Question: What is your interpretation of the model’s R-squared?
Using TV as the independent variable results in a linear regression model with R2 = 0.874. In other
words, the model explains 87.4% of the variation in Sales. This makes the model an effective
predictor of Sales.
Question: What is your intepretation of the coefficient estimates? Are the coefficients statistically
significant?
The default TV category for the model is High, because there are coefficients for the other two TV
categories, Medium and Low. According to the model, Sales with a Medium or Low TV category are
lower on average than Sales with a High TV category. For example, the model predicts that a Low
TV promotion would be 208.813 (in millions of dollars) lower in Sales on average than a High TV
promotion.
The p-value for all coefficients is 0.000, meaning all coefficients are statistically significant at p =
9
0.05. The 95% confidence intervals for each coefficient should be reported when presenting results
to stakeholders. For instance, there is a 95% chance the interval [−215.353, −202.274] contains the
true parameter of the slope of βT V Low , which is the estimated difference in promotion sales when
a Low TV promotion is chosen instead of a High TV promotion.
Question: Do you think your model could be improved? Why or why not? How?
Given how accurate TV was as a predictor, the model could be improved with a more granular
view of the TV promotions, such as additional categories or the actual TV promotion budgets.
Further, additional variables, such as the location of the marketing campaign or the time of year,
may increase model accuracy.
1.5.1 Perform a one-way ANOVA test
With the model fit, run a one-way ANOVA test to determine whether there is a statistically
significant difference in Sales among groups.
[28]: # Create an one-way ANOVA table for the fit model.
[Link].anova_lm(model, typ = 2)
[28]: sum_sq df F PR(>F)
C(TV) 4.052692e+06 2.0 1971.455737 8.805550e-256
Residual 5.817589e+05 566.0 NaN NaN
Hint
Use the anova_lm() function from [Link]. Specify the type of ANOVA test (for example,
one-way or two-way), using the typ parameter.
Question: What are the null and alternative hypotheses for the ANOVA test?
• H1: There is no difference in Sales based on the TV promotion budget.
• H2: There is a difference in Sales based on the TV promotion budget.
Question: What is your conclusion from the one-way ANOVA test?
The F-test statistic is 1971.46 and the p-value is 8.81 ∗ 10−256 (i.e., very small). Because the p-value
is less than 0.05, you would reject the null hypothesis that there is no difference in Sales based on
the TV promotion budget.
Question: What did the ANOVA test tell you?
The results of the one-way ANOVA test indicate that you can reject the null hypothesis in favor of
the alternative hypothesis. There is a statistically significant difference in Sales among TV groups.
1.5.2 Perform an ANOVA post hoc test
If you have significant results from the one-way ANOVA test, you can apply ANOVA post hoc tests
such as the Tukey’s HSD post hoc test.
10
Run the Tukey’s HSD post hoc test to compare if there is a significant difference between each pair
of categories for TV.
[30]: # Perform the Tukey's HSD post hoc test.
tukey_hsd = pairwise_tukeyhsd(endog = data['Sales'], groups = data['TV'])
tukey_hsd.summary()
[30]: <class '[Link]'>
Hint
Use the pairwise_tukeyhsd() function from [Link].
Hint 2
The endog argument in pairwise_tukeyhsd indicates which variable is being compared across
groups (i.e., Sales). The groups argument in pairwise_tukeyhsd tells the function which variable
holds the group you’re interested in reviewing.
Question: What is your interpretation of the Tukey HSD test?
The first row, which compares the High and Low TV groups, indicates that you can reject the null
hypothesis that there is no significant difference between the Sales of these two groups.
You can also reject the null hypotheses for the two other pairwise comparisons that compare High
to Medium and Low to Medium.
Question: What did the post hoc tell you?**
A post hoc test was conducted to determine which TV groups are different and how many are
different from each other. This provides more detail than the one-way ANOVA results, which can
at most determine that at least one group is different. Further, using the Tukey HSD controls for
the increasing probability of incorrectly rejecting a null hypothesis from peforming multiple tests.
The results were that Sales is not the same between any pair of TV groups.
1.6 Considerations
What are some key takeaways that you learned during this lab?
• Box-plots are a helpful tool for visualizing the distribution of a variable across groups.
• One-way ANOVA can be used to determine if there are significant differences among the
means of three or more groups.
• ANOVA post hoc tests provide a more detailed view of the pairwise differences between
groups.
What summary would you provide to stakeholders? Consider the statistical signifi-
cance of key relationships and differences in distribution.
High TV promotion budgets result in significantly more sales than both medium and low TV
promotion budgets. Medium TV promotion budgets result in significantly more sales than low TV
promotion budgets.
11
Specifically, following are estimates for the difference between the mean sales resulting from different
pairs of TV promotions, as determined by the Tukey’s HSD test:
• Estimated difference between the mean sales resulting from High and Low TV promotions:
\$208.81 million (with 95% confidence that the exact value for this difference is between
200.99 and 216.64 million dollars).
• Estimated difference between the mean sales resulting from High and Medium TV promotions:
\$101.51 million (with 95% confidence that the exact value for this difference is between 93.69
and 109.32 million dollars).
• difference between the mean sales resulting from Medium and Low TV promotions: \$107.31
million (with 95% confidence that the exact value for this difference is between 99.71 and
114.91 million dollars).
The linear regression model estimating Sales from TV had an R-squared of $0.871, making it a
fairly accurate estimator. The model showed a statistically significant relationship between the TV
promotion budget and Sales.
The results of the one-way ANOVA test indicate that the null hypothesis that there is no difference
in Sales based on the TV promotion budget can be rejected. Through the ANOVA post hoc test,
a significant difference between all pairs of TV promotions was found.
The difference in the distribution of sales across TV promotions was determined significant by both
a one-way ANOVA test and a Tukey’s HSD test.
Reference Saragih, H.S. Dummy Marketing and Sales Data
Congratulations! You’ve completed this lab. However, you may not notice a green check mark
next to this item on Coursera’s platform. Please continue your progress regardless of the check
mark. Just click on the “save” icon at the top of this notebook to ensure your work has been logged.
12