用 Python 进行数据分析2 - 统计学的方法
运用统计学的方法,我们希望得出一些结论,或者做出一些预测。
本文的不是为了介绍相关的知识,而是通过对观察和计算的过程进行记录,看看对于这个世界,我们是否能够发现一些什么。
为什么用 Python 而不是其他语言或者工具呢,主要是目前在使用,能实现目标就行。
而且实现方式多种多样,这里仅仅记录一种固定的可用的流程。
描述性统计
包括数据可视化。
这是最常用的方法,也做出数据初步的观察。结果以图表的形式呈现。
import pandas
df = pd.DataFrame({
"group": ["A", "A", "B", "B", "B"],
"score": [85, 90, 78, 88, 92]
})
print(df.describe())
print(df.mean())
print(df.sum())
print(df.groupby("group")["score"].describe())
数据可视化
画图可以用 matplotlib
对于 dataframe 为方便使用,可以用 pandas 或者 seaborn。他们仍然依赖于 matplotlib,需要一同使用。
注意 pandas 中每列是一组数据。而 seaborn 中有一列是分类变量,另一列是数据。
注意 pandas 隐含的 index 列,有时候要手工删除 index 列。
df = pd.DataFrame(np.random.randn(1000, 4), index=ts.index, columns=list("ABCD"))
df = df.cumsum()
plt.figure();
df.plot();
数据透视表。
分类汇总用数据透视表,比如分组取平均,也可以使用上面的 group 命令。
特殊的是每组只有一个数据的情况。
假设检验
有时候我们需要判断方法是否有效,某个变量是否会对结构带来差异。比如两组数的均值的差异是否足够大到反映两组数大小。
注意我们获得的数据是什么,能观察到,然后我们希望对什么结论做出判断。
假设检验是通过计算已知分布的统计量来拒绝原假设。
最常用的是对两组数据进行 t 检验,判断是否有显著性差异,进而判断某个方法是否有效果。
from scipy import stats
a = [82,78,85,76,80,79,83,77,81,75]
b = [88,85,90,83,87,84,89,86,82,85]
t_stat, p_value = stats.ttest_ind(a, b, equal_var=True)
print("t值:", t_stat) # 约-5.43
print("p值:", p_value) # 约0.00003(远小于0.05,拒绝H₀)
通常先手工计算平均值来比较,可以画出图表来比较。
如果是长表的话,可以先利用透视表,来分类汇总(比如求平均)。
import pandas as pd
from scipy import stats
# 展开group列,明确每个数据对应的组别
data = pd.DataFrame({
'value': [82,78,85,76,80,79,83,77,81,75, # A组数据
88,85,90,83,87,84,89,86,82,85], # B组数据
'group': ['A','A','A','A','A','A','A','A','A','A', # 对应A组的10个数据
'B','B','B','B','B','B','B','B','B','B'] # 对应B组的10个数据
})
# 查看数据
print("数据集(含展开的group列):")
print(data)
# 分组统计
print("\n分组统计描述:")
print(data.groupby('group')['value'].describe())
# 进行t检验
t_stat, p_value = stats.ttest_ind(
data[data['group'] == 'A']['value'],
data[data['group'] == 'B']['value'],
equal_var=True
)
print("\nt值:", t_stat) # 约-5.43
print("p值:", p_value) # 约0.00003(远小于0.05,拒绝H₀)
细分来说
- 按照样本数量,可以分为单样本检验,双样本检验,多样本检验。常见的是双样本检验。
- 按照验证的目标,均值差异是否显著,是否复合正态分布。最常用用的均值检验。
- 按照计算的统计量,t检验,F检验, chi2检验。
注意以上分类方法互有重叠。比如F检验可以用于双样本方差检验,也可用于多样本ANOVA,还可以用于回归分析的显著性。
对于正态分布,也可以使用直方图 和 QQplot 来观察。
常见假设检验的统计量以及分布
- t 分布 $T = \frac{Z}{\sqrt{\chi^2 / \nu}} \sim t(\nu).$,可以用于比较两组数的均值是否相等。
- F 分布 $F = \frac{U/d_1}{V/d_2} \sim F(d_1, d_2).$,其中 $U \sim \chi^2(d_1), \quad V \sim \chi^2(d_2),$,可以用于判断两样本方差是否相等,或者多样本均值是否相等。
- $\chi^2$ 分布 $\chi^2 = \sum_{i=1}^k Z_i^2 \sim \chi^2(k)$,可以用于判断两组频数是否相同,比如方法是否有效,或者是否满足均匀/正态分布
- Z 分布即标准正态分布 N(0,1),假设较为苛刻,不常用。
常见假设检验的方法
- 均值检验,用于判断样本均值与总体均值或两组样本均值之间是否有显著差异。
- 单样本 t 检验:检验样本均值是否等于某个已知值。
- 独立样本 t 检验:比较两组独立样本的均值差异。
- 配对样本 t 检验:比较两组相关(配对)的样本均值差异。
- Z 检验:样本量大且已知总体方差时用。
- 方差检验,检验不同组的方差是否相等。
- F 检验:比较两个总体方差是否相等。
- Bartlett 检验:多组数据方差齐性检验,对正态性要求较高。
- Levene 检验 / Brown-Forsythe 检验:多组数据方差齐性检验,更稳健。
- 分布检验,判断数据是否符合某种分布,比如正态分布。
- 卡方适配度检验(Chi-square goodness-of-fit test):检验样本分布与理论分布是否一致。
- Kolmogorov-Smirnov 检验(K-S 检验):检验样本是否来自某个分布。
- Shapiro-Wilk 检验:常用于正态性检验。
- Anderson-Darling 检验:另一种正态性检验。
- 比例检验,用于分类变量。
- 单样本比例检验(Binomial Test):样本比例是否等于某个理论值。
- 两样本比例检验(Two-proportion Z test):比较两组比例是否相等。
- 卡方独立性检验(Chi-square Test of Independence):判断两个分类变量是否独立。
- Fisher 精确检验:适合样本量较小的分类数据。
- 方差分析(ANOVA),检验三组及以上样本均值是否存在显著差异。
- 单因素方差分析(One-way ANOVA):比较单一因素下的多组均值。
- 双因素方差分析(Two-way ANOVA):考虑两个因素对结果的影响。
- 重复测量方差分析(Repeated Measures ANOVA):考虑同一样本在不同条件下的差异。
- 非参数检验(对分布无要求),适用于非正态分布或样本量小。
- Wilcoxon 秩和检验(Mann-Whitney U 检验):替代独立样本 t 检验。
- Wilcoxon 符号秩检验:替代配对样本 t 检验。
- Kruskal-Wallis 检验:替代单因素 ANOVA。
- Friedman 检验:替代重复测量 ANOVA。
其他代码
F 检验(比较方差,没有直接实现,用 lenve 代替),单因素方差分析 (ANOVA)
import numpy as np
from scipy import stats
# 两个组数据
group1 = [82, 78, 85, 76, 80, 79, 83, 77, 81, 75]
group2 = [88, 85, 90, 83, 87, 84, 89, 86, 82, 85]
# 计算样本方差
var1 = np.var(group1, ddof=1)
var2 = np.var(group2, ddof=1)
# F 统计量(较大方差 / 较小方差)
F = var1 / var2
# 自由度
df1 = len(group1) - 1
df2 = len(group2) - 1
# p 值(双尾)
p_val = 2 * min(stats.f.cdf(F, df1, df2), 1 - stats.f.cdf(F, df1, df2))
print("F 统计量:", F)
print("p 值:", p_val)
f_stat, p_val = stats.f_oneway(group1, group2)
print("单因素 ANOVA F:", f_stat, "p 值:", p_val)
卡方检验(Chi-square test)
import numpy as np
from scipy import stats
# 假设做了一个性别 vs 是否喜欢某产品的调查
# 行:性别(男,女),列:是否喜欢(喜欢,不喜欢)
data = np.array([[30, 10],
[20, 20]])
# 卡方独立性检验
chi2, p_val, dof, expected = stats.chi2_contingency(data)
print("卡方统计量:", chi2)
print("p 值:", p_val)
print("自由度:", dof)
print("期望频数:\n", expected)
卡方拟合优度检验 (chi-square goodness-of-fit test)
import numpy as np
from scipy import stats
# 假设掷骰子 60 次,记录各点数出现的频数
observed = np.array([8, 9, 10, 12, 11, 10]) # 实际观测值
# 理论均匀分布(每个点数出现的期望次数 = 总次数 / 6)
expected = np.ones(6) * observed.sum() / 6
# 卡方拟合优度检验
chi2, p_val = stats.chisquare(f_obs=observed, f_exp=expected)
print("卡方统计量:", chi2)
print("p 值:", p_val)
回归分析
回归分析可以从离散的数据中发现并总结出规律。
同时,其中的线性回归也是最简单的统计学习模型,可以用来对未知量进行预测。
多元线性回归
用 statsmodels 库
import pandas as pd
import statsmodels.api as sm
# 1. 准备数据
data = pd.DataFrame({
"area": [100, 150, 200, 250, 300],
"bedrooms": [2, 3, 3, 4, 4],
"price": [300, 500, 600, 800, 900]
})
X = data[["area", "bedrooms"]] # 自变量
y = data["price"] # 因变量
# 2. 加上常数项(截距)
X = sm.add_constant(X)
# 3. 建立回归模型并拟合
model = sm.OLS(y, X).fit()
# 4. 输出回归结果
print(model.summary())
用 sklearn 库
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
#示例数据(可替换为自己的数据集)
data = pd.DataFrame({
'x1': [1, 2, 3, 4, 5],
'x2': [2, 4, 5, 7, 8],
'y': [3, 5, 7, 9, 11]
})
X = data[['x1', 'x2']] #自变量
y = data['y'] #因变量
#划分训练集和测试集(可选,用于评估模型)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
#初始化模型
model = LinearRegression()
#用训练集训练
model.fit(X_train, y_train)
#查看系数和截距
print("系数:", model.coef_)
print("截距:", model.intercept_)
#预测(用测试集或新数据)
y_pred = model.predict(X_test)
print("预测值:", y_pred)
#评估模型(如R²,越接近1越好)
print("R²得分:", model.score(X_test, y_test))
用 statsmodels 库
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
import statsmodels.api as sm
# 准备数据
data = pd.DataFrame({
'x1': [1, 2, 3, 4, 5],
'x2': [2, 4, 5, 7, 8],
'y': [3, 5, 7, 9, 11]
})
X = data[['x1', 'x2']] #自变量
y = data['y'] #因变量
# statsmodels线性回归(含统计指标)
#添加常数项(截距项)
X_sm = sm.add_constant(X)
#拟合OLS模型
model_sm = sm.OLS(y, X_sm).fit()
#输出详细统计报告
print(model_sm.summary())
用 numpy 库
数学公式是 核心公式是:
$\hat{\beta} = (X^T X)^{-1} X^T y$
其中 $\hat{\beta}$ 就是回归系数(包括截距)。
import numpy as np
# 样本数据
# X1 = 房屋面积, X2 = 卧室数
X = np.array([
[100, 2],
[150, 3],
[200, 3],
[250, 4],
[300, 4]
])
y = np.array([300, 500, 600, 800, 900])
# 在 X 前面加一列 1(表示截距项)
X_b = np.c_[np.ones((X.shape[0], 1)), X] # shape (5,3)
# 正规方程解 (beta = (X^T X)^(-1) X^T y)
beta = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y)
print("回归系数(截距, 面积系数, 卧室数系数):")
print(beta)
# 用模型预测
y_pred = X_b.dot(beta)
print("预测值:", y_pred)
结果的可视化
一元线性回归可以直接作图。
模型的评估
- 方差分析,
- 残差
- 并不能反映有效性,可以调整。
用 ANOVA
https://www.statsmodels.org/stable/anova.html
ANOVA 使用 F 检验,计算对应的统计量。F 检验用来判断模型是否显著。零假设是系数都等于 0,对应的是至少有一个变量起作用。
对于单个变量,可以分别计算。
用 adjusted $R^2$
Confidence level
A numeric value between 0 and 1 (exclusive), default is 0.95. Calc uses this percentage to compute the corresponding confidence intervals for each of the estimates (namely the slopes and intercept).
Calculate residuals
Select whether to opt in or out of computing the residuals, which may be beneficial in cases where you are interested only in the slopes and intercept estimates and their statistics. The residuals give information on how far the actual data points deviate from the predicted data points, based on the regression model.
用其他库
一元线性回归
- 用 Scipy 中的模型
- 用 Seaborn 绘制图形。
其他回归分析
线性回归,对数回归,指数回归
广义线性回归
非线性回归
逻辑回归
因子分析
Factor
降维 PCA
旋转,可以让坐标的选择上增加解释性。
import numpy as np
import pandas as pd
from sklearn.decomposition import FactorAnalysis
from sklearn.preprocessing import StandardScaler
# 生成示例数据(或加载你的数据)
np.random.seed(42)
data = pd.DataFrame({
'x1': np.random.randn(100) + 0.5*np.random.randn(100),
'x2': np.random.randn(100) + 0.6*np.random.randn(100),
'x3': np.random.randn(100) - 0.4*np.random.randn(100),
'x4': np.random.randn(100) - 0.5*np.random.randn(100),
'x5': np.random.randn(100) + 0.3*np.random.randn(100)
})
# 数据标准化(因子分析通常需要标准化数据)
scaler = StandardScaler()
data_scaled = scaler.fit_transform(data)
# 初始化因子分析模型,指定因子数量
# 实际应用中,因子数量需要根据业务场景或特征值准则确定
n_factors = 2 # 假设选择2个因子
fa = FactorAnalysis(n_components=n_factors, random_state=42)
# 拟合模型并转换数据
data_factors = fa.fit_transform(data_scaled)
# 查看结果
print("因子载荷矩阵:\n", fa.components_.T) # 注意要转置
print("因子载荷矩阵(各变量在因子上的载荷):")
loadings = pd.DataFrame(
fa.components_.T, # 转置使每行对应一个原始变量
index=data.columns,
columns=[f'因子{i+1}' for i in range(n_factors)]
)
print(loadings)
print("\n转换后的因子数据(前5行):")
print(pd.DataFrame(data_factors, columns=[f'因子{i+1}' for i in range(n_factors)]).head())
如果需要更完整的因子分析流程(包括统计检验、旋转方法等),建议结合 factor_analyzer 库使用;若仅需基本的因子提取功能,scikit-learn 会更轻量且易于与其他机器学习流程集成。
从头到尾的完整流程包括 KMO、Bartlett 球形检验、碎石图、因子提取、旋转和结果解释。
完整的因子分析案例(带 KMO 检验 + 碎石图 + 因子载荷表 + 因子得分)
调查问卷
调查问卷由多到题目组成,对于单选题而言,回答是分类变量或者连续变量。
汇总收集到的数据,每行是一个调查问卷,每列是一个问题的回答。
进行分析的时候,往往要对分类变量进行数据透视表,来分析对连续变量的影响。
信度和效度
- 信度用 Cronbach’s Alpha
- 效度可以利用因子分析
- 主成分分析,最大方差旋转让各因子正交,
因果推断
其他场景
- 聚类与降维
- 时序分析
- 协方差
附录
参考资料
- https://www.gnu.org/software/pspp/manual/html_node/Statistics.html
- https://spssau.com/helps/
- https://help.libreoffice.org/24.8/en-US/text/scalc/01/statistics_test_f.html