Python 统计分析
引言
在数据科学和分析领域,统计分析是一项核心技能。Python凭借其丰富的统计库和简洁的语法,已成为统计分析的首选工具之一。本教程将带领初学者了解如何使用Python进行基本的统计分析,从描述性统计开始,逐步深入到更复杂的统计方法。
本教程假设你已经具备Python基础知识和简单的数学统计概念。如果你是完全的初学者,建议先学习Python基础和简单的统计学概念。
准备工作
在开始之前,我们需要安装几个关键的库:
pip install numpy pandas scipy matplotlib seaborn statsmodels
这些库将为我们提供进行统计分析所需的所有工具:
- NumPy: 用于数值计算
- Pandas: 用于数据处理和分析
- SciPy: 提供科学计算和高级统计功能
- Matplotlib 和 Seaborn: 用于数据可视化
- Statsmodels: 提供统计模型估计和假设检验
导入数据
统计分析的第一步通常是准备数据。让我们导入一个样本数据集:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats
# 设置可视化样式
sns.set(style="whitegrid")
# 创建一个简单的数据集
np.random.seed(42) # 设置随机种子,确保结果可复现
heights = np.random.normal(170, 10, 100) # 生成100个身高数据,均值170,标准差10
weights = heights * 0.6 + np.random.normal(0, 5, 100) # 基于身高生成相关的体重数据
# 创建DataFrame
df = pd.DataFrame({
'height': heights,
'weight': weights
})
print(df.head()) # 显示前5行数据
输出:
height weight
0 161.393096 93.916880
1 171.356213 99.028260
2 166.791478 99.961121
3 179.825745 111.856284
4 170.361087 101.797454
描述性统计
描述性统计是统计分析的基础,它帮助我们理解数据的基本特征。
基本统计量
# 计算基本统计量
stats_summary = df.describe()
print(stats_summary)
输出:
height weight
count 100.000000 100.000000
mean 169.583862 102.121777
std 10.419930 8.457169
min 146.857693 82.495144
25% 163.034019 96.189784
50% 169.178463 102.253893
75% 177.534282 107.720537
max 194.284452 122.249200
相关性分析
我们可以检查两个变量之间的相关性:
# 计算相关系数矩阵
correlation = df.corr()
print(correlation)
# 绘制热力图
plt.figure(figsize=(8, 6))
sns.heatmap(correlation, annot=True, cmap='coolwarm', vmin=-1, vmax=1)
plt.title('相关系数矩阵')
plt.show()
# 绘制散点图以直观展示关系
sns.jointplot(x='height', y='weight', data=df, kind='reg')
plt.show()
输出:
height weight
height 1.000000 0.884814
weight 0.884814 1.000000
这表明身高和体重之间有很强的正相关关系。
概率分布
理解数据的分布对于选择正确的统计方法至关重要。
正态分布检验
我们可以使用直方图和QQ图直观检查数据是否符合正态分布:
# 绘制身高的直方图
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
sns.histplot(df['height'], kde=True)
plt.title('身高分布直方图')
plt.subplot(1, 2, 2)
stats.probplot(df['height'], plot=plt)
plt.title('身高Q-Q图')
plt.tight_layout()
plt.show()
我们还可以使用Shapiro-Wilk测试来量化数据是否符合正态分布:
# 正态性检验
normality_test = stats.shapiro(df['height'])
print(f"Shapiro-Wilk测试结果 - 统计量: {normality_test[0]:.4f}, p值: {normality_test[1]:.4f}")
if normality_test[1] > 0.05:
print("根据Shapiro-Wilk测试,数据可能符合正态分布(未拒绝原假设)")
else:
print("根据Shapiro-Wilk测试,数据可能不符合正态分布(拒绝原假设)")
输出:
Shapiro-Wilk测试结果 - 统计量: 0.9881, p值: 0.5311
根据Shapiro-Wilk测试,数据可能符合正态分布(未拒绝原假设)
假设检验
假设检验是统计分析中用于决策制定的重要工具。
单样本t检验
假设我们想知道我们样本的平均身高是否与某个假设值(例如165厘米)有显著差异:
# 单样本t检验
t_stat, p_value = stats.ttest_1samp(df['height'], 165)
print(f"单样本t检验结果 - t值: {t_stat:.4f}, p值: {p_value:.4f}")
if p_value < 0.05:
print("拒绝原假设:样本平均值与165厘米有显著差异")
else:
print("未拒绝原假设:样本平均值与165厘米无显著差异")
# 计算均值和95%置信区间
mean_height = df['height'].mean()
confidence_interval = stats.t.interval(0.95, df.shape[0]-1, mean_height, df['height'].std()/np.sqrt(df.shape[0]))
print(f"平均身高: {mean_height:.2f} 厘米")
print(f"95%置信区间: ({confidence_interval[0]:.2f}, {confidence_interval[1]:.2f}) 厘米")
输出:
单样本t检验结果 - t值: 4.3934, p值: 0.0000
拒绝原假设:样本平均值与165厘米有显著差异
平均身高: 169.58 厘米
95%置信区间: (167.52, 171.65) 厘米
独立样本t检验
我们可以比较两组不同的数据:
# 创建两组数据进行比较
group1 = df['height'][:50] # 前50个样本
group2 = df['height'][50:] # 后50个样本
# 独立样本t检验
t_stat, p_value = stats.ttest_ind(group1, group2)
print(f"独立样本t检验结果 - t值: {t_stat:.4f}, p值: {p_value:.4f}")
if p_value < 0.05:
print("拒绝原假设:两组样本均值有显著差异")
else:
print("未拒绝原假设:两组样本均值无显著差异")
# 绘制箱线图比较两组数据
plt.figure(figsize=(8, 6))
sns.boxplot(x=['组1']*50 + ['组2']*50, y=np.concatenate([group1, group2]))
plt.title('两组身高数据的箱线图')
plt.xlabel('组别')
plt.ylabel('身高 (厘米)')
plt.show()
ANOVA(方差分析)
当我们需要比较三个或更多组的均值时,可以使用方差分析:
# 创建三组数据
group_a = np.random.normal(165, 10, 30)
group_b = np.random.normal(170, 10, 30)
group_c = np.random.normal(175, 10, 30)
# 进行单因素方差分析
f_stat, p_value = stats.f_oneway(group_a, group_b, group_c)
print(f"ANOVA测试结果 - F值: {f_stat:.4f}, p值: {p_value:.4f}")
if p_value < 0.05:
print("拒绝原假设:各组均值之间存在显著差异")
else:
print("未拒绝原假设:各组均值之间不存在显著差异")
# 可视化三组数据
plt.figure(figsize=(8, 6))
sns.boxplot(x=['A组']*30 + ['B组']*30 + ['C组']*30,
y=np.concatenate([group_a, group_b, group_c]))
plt.title('三组数据的箱线图')
plt.xlabel('组别')
plt.ylabel('值')
plt.show()
回归分析
回归分析用于探索变量之间的关系。
简单线性回归
import statsmodels.api as sm
# 为回归模型准备数据
X = df['height'] # 自变量
X = sm.add_constant(X) # 添加常数项(截距)
y = df['weight'] # 因变量
# 拟合线性回归模型
model = sm.OLS(y, X).fit()
print(model.summary())
# 预测和绘图
plt.figure(figsize=(10, 6))
sns.scatterplot(x='height', y='weight', data=df)
plt.plot(df['height'], model.predict(X), color='red')
plt.title('身高与体重的线性回归')
plt.xlabel('身高 (厘米)')
plt.ylabel('体重 (千克)')
plt.show()
输出将包含详细的回归分析结果,包括系数估计、p值、R²值等。
多元线性回归
在实际应用中,我们经常需要考虑多个自变量:
# 添加一个新的自变量:年龄
df['age'] = np.random.randint(18, 65, 100)
# 将身高和年龄作为自变量
X = df[['height', 'age']]
X = sm.add_constant(X) # 添加常数项
y = df['weight'] # 因变量
# 拟合多元线性回归模型
model = sm.OLS(y, X).fit()
print(model.summary())
应用实例:数据分析项目
让我们通过一个实际的项目来整合我们学到的概念。假设我们有一组学生的学习数据(学习时间、课外活动时间和考试分数):
# 创建学生数据
np.random.seed(42)
study_time = np.random.normal(3, 1, 50) # 每天学习时间,平均3小时
activity_time = np.random.normal(2, 0.5, 50) # 每天课外活动时间,平均2小时
error = np.random.normal(0, 10, 50) # 随机误差
exam_score = 60 + 8 * study_time - 3 * activity_time + error # 考试分数模型
# 确保分数在合理范围内
exam_score = np.clip(exam_score, 0, 100)
student_df = pd.DataFrame({
'study_time': study_time,
'activity_time': activity_time,
'exam_score': exam_score
})
print(student_df.head())
# 1. 描述性统计
print("\n描述性统计:")
print(student_df.describe())
# 2. 相关性分析
print("\n相关性分析:")
print(student_df.corr())
# 3. 数据可视化
plt.figure(figsize=(12, 8))
# 学习时间与考试分数的关系
plt.subplot(2, 2, 1)
sns.scatterplot(x='study_time', y='exam_score', data=student_df)
plt.title('学习时间与考试分数')
# 课外活动时间与考试分数的关系
plt.subplot(2, 2, 2)
sns.scatterplot(x='activity_time', y='exam_score', data=student_df)
plt.title('课外活动时间与考试分数')
# 考试分数的分布
plt.subplot(2, 2, 3)
sns.histplot(student_df['exam_score'], kde=True)
plt.title('考试分数分布')
# 学习时间与活动时间的关系
plt.subplot(2, 2, 4)
sns.scatterplot(x='study_time', y='activity_time', data=student_df)
plt.title('学习时间与活动时间的关系')
plt.tight_layout()
plt.show()
# 4. 多元回归分析
X = student_df[['study_time', 'activity_time']]
X = sm.add_constant(X)
y = student_df['exam_score']
model = sm.OLS(y, X).fit()
print("\n回归分析结果:")
print(model.summary())
# 5. 预测
new_students = pd.DataFrame({
'const': [1, 1, 1],
'study_time': [2, 4, 3],
'activity_time': [3, 1, 2]
})
predictions = model.predict(new_students)
print("\n预测结果:")
for i, pred in enumerate(predictions):
print(f"学生{i+1}预测分数:{pred:.2f}")
总结
在本教程中,我们学习了如何使用Python进行基本的统计分析,包括:
- 描述性统计:了解数据的基本特征
- 概率分布:检查数据的分布情况
- 假设检验:验证关于数据的假设
- 回归分析:探索变量之间的关系
- 实际应用:整合各种方法进行数据分析
Python提供了丰富的统计分析工具,使得我们可以轻松地进行各种复杂的统计计算。随着你的技能提升,你可以探索更高级的统计方法和更复杂的模型。
统计分析不仅仅是运行代码和获取结果,更重要的是理解结果的含义并做出正确的解释。始终记住:相关性并不意味着因果关系!
练习
- 使用
iris
数据集(可通过seaborn.load_dataset('iris')
加载)进行描述性统计分析。 - 比较
iris
数据集中不同种类的花瓣长度,使用ANOVA检验它们是否有显著差异。 - 构建一个线性回归模型,预测花瓣长度基于萼片长度和宽度。
- 探索自己感兴趣的数据集,进行完整的统计分析,并撰写分析报告。
额外资源
Python统计分析是一个广阔的领域,本教程只是一个入门。随着你对Python和统计学的深入了解,你将能够处理更复杂的数据分析任务。