Recently, I was working on a data analysis project where I needed to determine if two groups of data were statistically different from each other. The question was simple: Does our new machine learning algorithm perform better than the traditional one? That’s when I turned to SciPy’s ttest_ind function.
In this article, I’ll walk you through how to use the ttest_ind function in Python’s SciPy library to compare means between two independent samples. I’ll cover practical examples, explain the output, and give you tips from my decade of experience with statistical testing in Python.
So let’s start…!
What is ttest_ind and Why Use It?
The ttest_ind function in SciPy implements the independent t-test (also known as Student’s t-test), which helps us determine if there’s a significant difference between the means of two independent groups.
Think of it as your “coincidence detector.” It helps answer questions like: “Is the difference between these two groups just due to random chance, or is there something meaningful happening?”
For example, suppose you want to know if a new Python training course improves developers’ coding speed:
- Group A: Developers who took the training
- Group B: Developers who didn’t take the training
After measuring how quickly each group completes a coding task, you notice Group A seems faster, but you’re not sure if it’s because of the training or just by chance.
This is exactly where ttest_ind comes in handy!
Read SciPy Stats
Basic Usage of ttest_ind
Here’s how you can use the ttest_ind function in its simplest form:
from scipy import stats
import numpy as np
# Sample data: time to complete a task (in minutes)
group_a = np.array([15, 12, 19, 15, 21, 17, 18, 13, 16, 14]) # Trained developers
group_b = np.array([22, 25, 17, 24, 16, 29, 20, 23, 19, 20]) # Untrained developers
# Perform the t-test
t_stat, p_value = stats.ttest_ind(group_a, group_b)
print(f"t-statistic: {t_stat:.4f}")
print(f"p-value: {p_value:.4f}")This code would output something like:
t-statistic: -3.6135
p-value: 0.0020I executed the above example code and added the screenshot below.

Since our p-value is less than 0.05 (a commonly used threshold), we can reject the null hypothesis. This suggests that the Python training did have a significant impact on coding speed!
Check out SciPy Misc
Advanced Options in ttest_ind
SciPy’s ttest_ind function offers several parameters that make it flexible for different scenarios:
Equal Variance vs. Unequal Variance
By default, ttest_ind assumes equal variance between groups, but you can change this:
# For unequal variance (Welch's t-test)
t_stat, p_value = stats.ttest_ind(group_a, group_b, equal_var=False)When should you use each option?
- Use
equal_var=True(default) when you believe both groups have similar variability - Use
equal_var=Falsewhen you’re unsure or suspect different variability between groups
In our developer example, if one group had more experienced programmers (less variability in completion times), we might use equal_var=False.
Check out SciPy Integrate
One-Tailed vs. Two-Tailed Test
In newer versions of SciPy, you can specify alternative hypotheses:
# One-tailed test (group_a has smaller values than group_b)
t_stat, p_value = stats.ttest_ind(group_a, group_b, alternative='less')
# One-tailed test (group_a has larger values than group_b)
t_stat, p_value = stats.ttest_ind(group_a, group_b, alternative='greater')
# Two-tailed test (default)
t_stat, p_value = stats.ttest_ind(group_a, group_b, alternative='two-sided')When to use each option:
- Use ‘less’ when you’re specifically testing if the first group has smaller values
- Use ‘greater’ when you’re specifically testing if the first group has larger values
- Use ‘two-sided’ when you’re open to differences in either direction
Read SciPy Signal
Real-World Examples with ttest_ind
Let’s look at a more detailed example with real-world context:
import pandas as pd
from scipy import stats
import matplotlib.pyplot as plt
# Load sample data (you'd load your own data in practice)
data = {
'Group': ['A']*30 + ['B']*30,
'Response_Time': [
# Response times for web application A (milliseconds)
120, 115, 122, 125, 130, 119, 121, 129, 124, 118,
114, 125, 126, 130, 120, 132, 121, 119, 122, 127,
118, 120, 123, 125, 121, 126, 124, 120, 118, 122,
# Response times for web application B (milliseconds)
142, 139, 145, 143, 140, 141, 144, 139, 138, 143,
146, 135, 142, 140, 138, 139, 143, 141, 142, 147,
140, 143, 141, 139, 145, 142, 139, 144, 138, 140
]
}
df = pd.DataFrame(data)
# Get data for each group
group_a = df[df['Group'] == 'A']['Response_Time']
group_b = df[df['Group'] == 'B']['Response_Time']
# Perform t-test
t_stat, p_value = stats.ttest_ind(group_a, group_b)
# Visualize the data
plt.figure(figsize=(10, 6))
plt.boxplot([group_a, group_b], labels=['App A', 'App B'])
plt.ylabel('Response Time (ms)')
plt.title('Web Application Response Times')
plt.savefig('response_times.png') # Save the figure
plt.close()
# Print results with interpretation
print(f"Mean response time App A: {group_a.mean():.2f} ms")
print(f"Mean response time App B: {group_b.mean():.2f} ms")
print(f"t-statistic: {t_stat:.4f}")
print(f"p-value: {p_value:.8f}")
if p_value < 0.05:
print("The difference in response times is statistically significant.")
else:
print("There is no significant difference in response times.")I executed the above example code and added the screenshot below.

This comprehensive example loads data, performs the t-test, creates a visualization, and provides an interpretation of the results.
Read SciPy Convolve
Interpret the Results
Understanding the output of ttest_ind is crucial:
- t-statistic: Indicates how many standard errors the two means are apart. A larger absolute value suggests a bigger difference.
- p-value: The probability of seeing this difference (or more extreme) if there was no actual difference between groups. Typically:
- p < 0.05: Statistically significant difference
- p < 0.01: Highly significant difference
- p < 0.001: Very highly significant difference
Remember that statistical significance doesn’t always mean practical significance. A tiny difference could be statistically significant with large enough samples, but might not matter in the real world.
Also, the t-test assumes your data is normally distributed. If your data violates this assumption, consider non-parametric alternatives like the Mann-Whitney U test (implemented as scipy.stats.mannwhitneyu).
When working with the ttest_ind function, I’ve found it’s always a good practice to visualize your data (using histograms or box plots) before running the test. This helps you spot potential issues and better understand your results.
The SciPy ttest_ind function is an incredibly useful tool for comparing means between two independent groups. Whether you’re comparing algorithm performance, drug effectiveness, or website conversion rates, this test helps you move beyond “looks different” to “is statistically different.”
Other Python statistics articles you may also like:

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.