跳到主要内容

Python 统计分析

引言

在数据科学和分析领域,统计分析是一项核心技能。Python凭借其丰富的统计库和简洁的语法,已成为统计分析的首选工具之一。本教程将带领初学者了解如何使用Python进行基本的统计分析,从描述性统计开始,逐步深入到更复杂的统计方法。

备注

本教程假设你已经具备Python基础知识和简单的数学统计概念。如果你是完全的初学者,建议先学习Python基础和简单的统计学概念。

准备工作

在开始之前,我们需要安装几个关键的库:

bash
pip install numpy pandas scipy matplotlib seaborn statsmodels

这些库将为我们提供进行统计分析所需的所有工具:

  • NumPy: 用于数值计算
  • Pandas: 用于数据处理和分析
  • SciPy: 提供科学计算和高级统计功能
  • MatplotlibSeaborn: 用于数据可视化
  • Statsmodels: 提供统计模型估计和假设检验

导入数据

统计分析的第一步通常是准备数据。让我们导入一个样本数据集:

python
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

描述性统计

描述性统计是统计分析的基础,它帮助我们理解数据的基本特征。

基本统计量

python
# 计算基本统计量
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

相关性分析

我们可以检查两个变量之间的相关性:

python
# 计算相关系数矩阵
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图直观检查数据是否符合正态分布:

python
# 绘制身高的直方图
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测试来量化数据是否符合正态分布:

python
# 正态性检验
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厘米)有显著差异:

python
# 单样本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检验

我们可以比较两组不同的数据:

python
# 创建两组数据进行比较
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(方差分析)

当我们需要比较三个或更多组的均值时,可以使用方差分析:

python
# 创建三组数据
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()

回归分析

回归分析用于探索变量之间的关系。

简单线性回归

python
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²值等。

多元线性回归

在实际应用中,我们经常需要考虑多个自变量:

python
# 添加一个新的自变量:年龄
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())

应用实例:数据分析项目

让我们通过一个实际的项目来整合我们学到的概念。假设我们有一组学生的学习数据(学习时间、课外活动时间和考试分数):

python
# 创建学生数据
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进行基本的统计分析,包括:

  1. 描述性统计:了解数据的基本特征
  2. 概率分布:检查数据的分布情况
  3. 假设检验:验证关于数据的假设
  4. 回归分析:探索变量之间的关系
  5. 实际应用:整合各种方法进行数据分析

Python提供了丰富的统计分析工具,使得我们可以轻松地进行各种复杂的统计计算。随着你的技能提升,你可以探索更高级的统计方法和更复杂的模型。

提示

统计分析不仅仅是运行代码和获取结果,更重要的是理解结果的含义并做出正确的解释。始终记住:相关性并不意味着因果关系!

练习

  1. 使用iris数据集(可通过seaborn.load_dataset('iris')加载)进行描述性统计分析。
  2. 比较iris数据集中不同种类的花瓣长度,使用ANOVA检验它们是否有显著差异。
  3. 构建一个线性回归模型,预测花瓣长度基于萼片长度和宽度。
  4. 探索自己感兴趣的数据集,进行完整的统计分析,并撰写分析报告。

额外资源

Python统计分析是一个广阔的领域,本教程只是一个入门。随着你对Python和统计学的深入了解,你将能够处理更复杂的数据分析任务。