全部版块 我的主页
论坛 数据科学与人工智能 数据分析与数据科学 python论坛
327 0
2025-11-19

Python 统计分析实战:从单组到多组数据的深入探究

在数据解析领域,对比和研究不同组的数据是一项极其重要的工作。无论是在评估药物疗效、探讨不同处理对植物成长的影响,还是分析气温与年度间的关系,恰当的统计方法都是必不可少的。本文将详尽介绍如何利用 Python 对单组和多组数据进行对比、分类数据的分析以及相关性和回归分析,并解释一些关键的统计术语。

1. 单组和两组数据比较

1.1 单组数据均值检验

在处理单组数据时,我们经常需要检查其平均值是否与某一参考值有显著差异。以下是使用 Python 实现这一检验的代码:

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
import scipy as sp
import os

def oneGroup():
    print('Single group of data')
    print('=========================================')
    data = np.array([5260, 5470, 5640, 6180, 6390, 6515,
                     6805, 7515, 7515, 8230, 8770], dtype=np.float)
    checkValue = 7725

    # 4.1.1. 正态性检验
    (_, p) = stats.normaltest(data)
    if p > 0.05:
        print('Data are distributed normally, p = {0}'.format(p))

    # 4.1.2. 单样本 t 检验
    t, prob = stats.ttest_1samp(data, checkValue)
    if prob < 0.05:
        print('With the one-sample t-test, {0:4.2f} is significantly different from the mean (p={1:5.3f}).'.format(checkValue, prob))
    else:
        print('No difference from reference value with onesample t-test.')

    # 4.1.3. Wilcoxon 检验
    (_, p) = stats.wilcoxon(data - checkValue)
    if p < 0.05:
        print('With the Wilcoxon test, {0:4.2f} is significantly different from the mean (p={1:5.3f}).'.format(checkValue, p))
    else:
        print('No difference from reference value with Wilcoxon rank sum test.')

if __name__ == '__main__':
    oneGroup()

上述代码的执行步骤如下:

  1. 数据准备:定义单组数据
    data
    和参考值
    checkValue
  2. 正态性检验:使用
    stats.normaltest
    函数检验数据是否符合正态分布。如果
    p
    值大于 0.05,则认为数据呈现正态分布。
  3. 单样本 t 检验:使用
    stats.ttest_1samp
    函数检验数据平均值与参考值是否有显著差异。如果
    p
    值小于 0.05,则认为存在显著差异。
  4. Wilcoxon 检验:使用
    stats.wilcoxon
    函数检验数据与参考值的差异是否显著。如果
    p
    值小于 0.05,则认为存在显著差异。

1.2 两组数据均值比较

当需要对比两组数据的平均值时,可以使用以下代码:

def twoGroups():
    print('Two groups of data')
    print('=========================================')
    data1 = [76., 101., 66., 72., 88., 82., 79., 73., 76., 85., 75., 64., 76., 81., 86.]
    data2 = [64., 65., 56., 62., 59., 76., 66., 82., 91., 57., 92., 80., 82., 67., 54.]

    # 正态性检验
    print('\n Normality test')
    print('--------------------------------------------------')
    for ii, data in enumerate((data1, data2)):
        (_, pval) = stats.normaltest(data)
        if pval > 0.05:
            print('Dataset # {0} is normally distributed'.format(ii))

    # 独立样本 t 检验
    print('\n T-test of independent samples')
    print('-------------------------------------------')
    t, pval = stats.ttest_ind(data1, data2)
    if pval < 0.05:
        print('With the T-test, data1 and data2 are significantly different (p = {0:5.3f})'.format(pval))
    else:
        print('No difference between data1 and data2 with T-test.')

    # Mann-Whitney 检验
    print('\n Mann-Whitney test')
    print('------------------------------------------------------')
    if np.int(sp.__version__.split('.')[1]) > 16:
        u, pval = stats.mannwhitneyu(data1, data2, alternative='two-sided')
    else:
        u, pval = stats.mannwhitneyu(data1, data2)
        pval *= 2
    if pval < 0.05:
        print('With the Mann-Whitney test, data1 and data2 are significantly different(p = {0:5.3f})'.format(pval))
    else:
        print('No difference between data1 and data2 with Mann-Whitney test.')

if __name__ == '__main__':
    twoGroups()

该代码的执行步骤如下:

  1. 数据准备:定义两组数据
    data1
    data2
  2. 正态性检验:对两组数据分别进行正态性检验,使用
    stats.normaltest
    函数。
  3. 独立样本 t 检验:使用
    stats.ttest_ind
    函数检验两组数据的平均值是否有显著差异。如果
    p
    值小于 0.05,则认为存在显著差异。
  4. Mann-Whitney 检验:使用
    stats.mannwhitneyu
    函数进行非参数检验。根据
    scipy
    版本的不同,处理方式有所不同。如果
    p
    值小于 0.05,则认为两组数据存在显著差异。

1.3 多组数据比较

在实际应用中,我们可能需要对比多组数据的平均值。以下是使用 Python 进行多组数据比较的代码:

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
import pandas as pd
from statsmodels.formula.api import ols
from statsmodels.stats.anova import anova_lm
from statsmodels.stats import multicomp
import xlrd

def get_ANOVA_data():
    inFile = 'Table 6.6 Plant experiment.xls'
    book = xlrd.open_workbook(inFile)
    sheet = book.sheet_by_index(0)
    treatment = sheet.col_values(4)
    weight = sheet.col_values(5)
    data = pd.DataFrame({'group': treatment[3:], 'weight': weight[3:]})
    return data

def do_ANOVA(data):
    print('ANOVA:')
    print('----------------------------------------------')
    model = ols('weight ~ C(group)', data).fit()
    anovaResults = anova_lm(model)
    print(anovaResults)
    if anovaResults['PR(>F)'][0] < 0.05:
        print('One of the groups is different.')

def compare_many(data):
    print('\n MultComp:')
    print('--------------------------------------')
    mc = multicomp.MultiComparison(data['weight'], data['group'])
    print(mc.tukeyhsd().summary())
    print(mc.groupsunique)

    res2 = mc.tukeyhsd()
    simple = False
    if simple:
        res2.plot_simultaneous()
    else:
        xvals = np.arange(3)
        plt.plot(xvals, res2.meandiffs, 'o')
        errors = np.ravel(np.diff(res2.confint) / 2)
        plt.errorbar(xvals, res2.meandiffs, yerr=errors, fmt='o')
        xlim = -0.5, 2.5
        plt.hlines(0, *xlim)
        plt.xlim(*xlim)
        pair_labels = mc.groupsunique[np.column_stack(res2._multicomp.pairindices)]
        plt.xticks(xvals, pair_labels)
        plt.title('Multiple Comparison of Means - Tukey HSD, FWER=0.05' + '\n Pairwise Mean Differences')
        plt.show()

def KruskalWallis(data):
    print('\n Kruskal-Wallis test')
    print('----------------------------------------------------')
    g_a = data['weight'][data['group'] == 'TreatmentA']
    g_b = data['weight'][data['group'] == 'TreatmentB']
    g_c = data['weight'][data['group'] == 'Control']
    h, p = stats.kruskal(g_c, g_a, g_b)
    print('Result from Kruskal-Wallis test: p = {0}'.format(p))

if __name__ == '__main__':
    data = get_ANOVA_data()
    do_ANOVA(data)
    compare_many(data)
    KruskalWallis(data)

上述代码的执行流程如下:

graph TD;
    A[获取数据] --> B[进行 ANOVA 分析];
    B --> C[多重比较];
    C --> D[Kruskal-Wallis 检验];
  1. 数据获取:使用
    get_ANOVA_data
    函数从 Excel 文件中读取数据,并将其存储在
    pandas
    DataFrame
    中。
  2. ANOVA 分析:使用
    do_ANOVA
    函数进行方差分析,判断多组数据的平均值是否有显著差异。如果
    PR(>F)
    值小于 0.05,则认为至少有一组数据与其他组不同。
  3. 多重比较:使用
    compare_many
    函数进行多重比较,找出具体哪些组之间存在差异。这里使用了 Tukey’s Honest Significant Difference 检验,并绘制了可视化图形。
  4. Kruskal-Wallis 检验:使用
    KruskalWallis
    函数进行非参数检验,判断多组数据是否来自相同的分布。

2. 分类数据的分析

2.1 Fisher 精确检验

Fisher 精确检验通常用于分析分类数据,特别是在样本量较小的情况下。以下是使用 Python 进行 Fisher 精确检验的代码:

from scipy import stats

obs = [[3, 1], [1, 3]]
_, p = stats.fisher_exact(obs, alternative='greater')
print('\n--- A Lady Tasting Tea (Fisher Exact Test) ---')
print('The chance that the lady selects 3 or more cups correctly by chance is {0:5.3f}'.format(p))

上述代码的执行步骤如下:

  1. 数据准备:定义观测数据
    obs
  2. Fisher 精确检验:使用
    stats.fisher_exact
    函数进行检验,设置
    alternative='greater'
    表示单侧检验。
  3. 结果输出:打印出女士随机选择 3 杯或更多正确杯子的概率。

2.2 Chi2 列联表检验

Chi2 列联表检验用于分析两个分类变量之间的关联性。以下是使用 Python 进行 Chi2 列联表检验的代码:

from scipy import stats

obs = [[36, 14], [30, 25]]
chi2, p, dof, expected = stats.chi2_contingency(obs)
print('--- Contingency Test ---')
if p < 0.05:
    print('p={0:6.4f}: the drug affects the heart rate.'.format(p))
else:
    print('p={0:6.4f}: the drug does NOT affect the heart rate.'.format(p))

obs2 = [[36, 14], [29, 26]]
chi2, p, dof, expected = stats.chi2_contingency(obs2)
chi2, p2, dof, expected = stats.chi2_contingency(obs2, correction=False)
print('If the response in 1 non - treated person were different, \n we would get p={0:6.4f} with Yates correction, and p={1:6.4f} without.'.format(p, p2))

上述代码的执行步骤如下:

  1. 数据准备:定义观测数据
    obs
    obs2
  2. Chi2 列联表检验:使用
    stats.chi2_contingency
    函数进行检验,得到卡方值、
    p
    值、自由度和期望频数。
  3. 结果判断:根据
    p
    值判断药物是否影响心率。
  4. Yates 校正:对
    obs2
    数据进行有 Yates 校正和无 Yates 校正的检验,并输出结果。

2.3 Chi2 单向检验

Chi2 单向检验用于检验多个分类变量的分布是否有显著差异。以下是使用 Python 进行 Chi2 单向检验的代码:

from scipy import stats

obs = [4, 6, 14, 10, 16]
_, p = stats.chisquare(obs)
print('\n--- Chi2-oneway ---')
if p < 0.05:
    print('The difference in opinion between the different age groups is significant (p={0:6.4f})'.format(p))
else:
    print('The difference in opinion between the different age groups is NOT significant (p={0:6.4f})'.format(p))
print('DOF={0:3d}'.format(len(obs) - 1))

上述代码的执行步骤如下:

  1. 数据准备:定义观测数据
    obs
  2. Chi2 单向检验:使用
    stats.chisquare
    函数进行检验,得到
    p
    值。
  3. 结果判断:根据
    p
    值判断不同年龄组之间的意见差异是否显著,并输出自由度。

2.4 McNemar 检验

McNemar 检验用于分析配对的分类数据。以下是使用 Python 进行 McNemar 检验的代码:

from scipy import stats
from statsmodels.sandbox.stats.runs import mcnemar

obs = [[19, 1], [6, 14]]
obs2 = [[20, 0], [6, 14]]
_, p = mcnemar(obs)
_, p2 = mcnemar(obs2)
print('\n--- McNemar Test ---')
if p < 0.05:
    print('The results from the neurologist are significantly different from the questionnaire (p={0:5.3f}).'.format(p))
else:
    print('The results from the neurologist are NOT significantly different from the questionnaire (p={0:5.3f}).'.format(p))
if (p < 0.05 == p2 < 0.05):
    print('The results would NOT change if the expert had diagnosed all "sane" people correctly.')
else:
    print('The results would change if the expert had diagnosed all "sane" people correctly.')

上述代码的执行步骤如下:

  1. 数据准备:定义观测数据
    obs
    obs2

McNemar 检验: 使用

mcnemar
函数对两组资料进行检验,获得
p
值。

3. 结果判定: 根据

p
值评估神经科医师的诊断结果与问卷结果是否存在显著差异,并探讨如果专家准确诊断所有“正常”群体,结果是否会有所变化。

3. 相关性和回归分析

3.1 相关性分析

数据分析过程中,我们经常需要考察两个变量之间的关联性。以下是运用 Python 进行相关性分析的代码:

import numpy as np
import pandas as pd
from scipy import stats
import matplotlib.pyplot as plt
import seaborn as sns

def getModelData(show=True):
    in_file = 'AvgTemp.xls'
    xls = pd.ExcelFile(in_file)
    data = xls.parse('Tabelle1')
    if show:
        data.plot('year', 'AvgTmp')
        plt.xlabel('Year')
        plt.ylabel('Average Temperature')
        plt.show()
    return data

if __name__ == '__main__':
    data = getModelData()
    print('Pearson correlation coefficient: {0:5.3f}'.format(data['year'].corr(data['AvgTmp'], method='pearson')))
    print('Spearman correlation coefficient: {0:5.3f}'.format(data['year'].corr(data['AvgTmp'], method='spearman')))
    print('Kendall tau: {0:5.3f}'.format(data['year'].corr(data['AvgTmp'], method='kendall')))

上述代码的执行流程如下:

1. 数据收集: 利用

getModelData
函数从 Excel 文件中导入数据,并可选择生成可视化图表。

2. 相关性计算: 分别计算 Pearson 相关系数、Spearman 相关系数和 Kendall tau 值,采用

corr
函数并指定不同方法。

3. 结果展示: 输出三种相关性系数的具体数值。

3.2 回归分析

回归分析用于构建变量间的数学模型,预测因变量的值。以下是利用 Python 实施回归分析的代码:

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
import seaborn as sns
import statsmodels.formula.api as sm
from S11_correlation import getModelData

if __name__ == '__main__':
    data = getModelData(show=False)
    model = sm.ols('AvgTmp ~ year', data)
    results = model.fit()
    print(results.summary())
    sns.lmplot('year', 'AvgTmp', data)
    plt.show()
    ci = results.conf_int()
    if np.prod(ci.loc['year']) > 0:
        print('The slope is significant')

上述代码的执行流程如下:

1. 数据收集: 利用

getModelData
函数从 Excel 文件中读取数据。

2. 回归模型构建: 采用

sm.ols
函数创建普通最小二乘回归模型,指定公式
'AvgTmp ~ year'

3. 模型拟合: 利用

fit
方法拟合模型,并输出模型的概要信息。

4. 可视化: 利用

seaborn
lmplot
函数绘制回归直线及其置信区间。

5. 斜率显著性评估: 通过计算置信区间的乘积,判断斜率是否具有显著性。

3.3 正态性检验

在进行回归分析时,通常需验证残差是否符合正态分布。以下是运用 Python 进行正态性检验的代码:

from scipy import stats
import matplotlib.pyplot as plt
import statsmodels.formula.api as sm
import seaborn as sns
from S11_correlation import getModelData

if __name__ == '__main__':
    data = getModelData(show=False)
    model = sm.ols('AvgTmp ~ year', data)
    results = model.fit()
    res_data = results.resid
    stats.probplot(res_data, plot=plt)
    plt.show()
    _, pVal = stats.normaltest(res_data)
    if pVal < 0.05:
        print('WARNING: The data are not normally distributed (p = {0})'.format(pVal))
    else:
        print('Data are normally distributed.')

上述代码的执行流程如下:

1. 数据收集和模型拟合: 同回归分析部分,获取数据并拟合回归模型。

2. 残差获取: 从拟合结果中提取残差数据。

3. QQ 图绘制: 利用

stats.probplot
函数绘制 QQ 图,直观检查残差是否符合正态分布。

4. 正态性检验: 利用

stats.normaltest
函数进行正态性检验,依据
p
值判断残差是否符合正态分布。

4. 重要统计术语解析

为了更深入地理解上述统计分析方法,以下是一些关键统计术语的说明:

术语解释
偏差(bias)样本统计数据与对应总体统计数据的系统性偏差,通常由样本选取不当引起。
区组化(blocking)通过固定某变量来减少其变异,该变量无法进行随机化处理。
箱线图(box - plot)一种常用的数据分布可视化方式,用一条带有线条的盒状图形表示。盒子表示第一和第三四分位数,线条表示中位数,线条可以表示数据范围或在 1.5 倍四分位距内的最极端值。
病例对照研究(case–control study)一种观察性研究,先确定两个结果不同的现有组,然后基于某些假设的因果属性进行对比。
分类数据(categorical data)只能取有限且通常固定数量的可能值,且没有自然排序的数据。
队列研究(cohort study)一种观察性研究,先选定患者,随后追踪其发展。例如,在医学领域,队列研究先分析风险因素,然后追踪一组未患病个体,最终通过相关性确定患病的绝对风险。
置信区间(confidence interval)对总体参数的区间估计,包含参数真实值的概率为指定百分比(如 95% - CI)。
相关性(correlation)两个或多个随机变量偏离独立性的程度。
交叉研究(crossover study)一种纵向研究,所有参与者依次接受不同的治疗。
累积分布函数(cumulative distribution function)随机变量取值小于给定值的概率。
自由度(degrees of freedom)统计量最终计算中能自由变化的值的数量。
密度(density)描述随机变量取特定值相对可能性的连续函数,如核密度估计(KDE)或概率密度函数(PDF)。
设计矩阵(design matrix)回归模型
y = X * β + ε
中的数据矩阵
X
分布(distribution)为随机试验的每个可测量子集分配概率的函数。
实验研究(experimental study)研究者能够控制参与者选择和研究条件的研究。
因子(factor)也称作处理或自变量,是实验者操控的解释变量。
函数(function)接收输入数据、执行指令和计算,并可返回一个或多个输出对象的 Python 对象。
假设检验(hypothesis test)用于检验统计假设的统计推理方法。
峰度(kurtosis)衡量分布尖锐度的指标,正态分布的峰度约为 3。“超峰度”是指相对于正态分布的峰度。

|线性回归(linear regression)|采用线性预测函数对单一变量(因变量)进行建模,未知的模型参数通过数据估算。简单线性回归:

y = k * x + d

;多元线性回归:
y = k1 * x1 + k2 * x2 + ... + kn * xn + d

。|

|位置(location)|调整概率分布平均值的参数。|

|逻辑回归(logistic regression)|又称 logit 回归,利用逻辑函数对单次试验的结果概率进行建模,作为预测(解释)变量的函数:

f(x) = L / (1 + e^(-k(x - x0)))

。|

|马尔可夫链(Markov Chain)|一种随机过程模型,每个状态的概率仅依赖于前一状态。|

|最大似然(maximum likelihood)|针对固定的数据集和统计模型,最大似然方法选取使似然函数最大的模型参数值。直白地讲,这使选定模型与观察数据的“契合度”达到最大,对于离散随机变量,它确实使观察数据在所得分布下的概率最大化。|

|中位数(median value)|将数据样本分割成上下两半的数值。|

|最小化(minimization)|与随机化紧密相连,选择参与人数最少的处理方式,并以超过 0.5 的概率将此处理分配给下一参与者。|

|众数(mode value)|离散或连续概率分布中的峰值。|

|模块(module)|含有 Python 变量和函数定义的文档。|

|蒙特卡罗模拟(Monte Carlo Simulation)|基于对随机变量的反复抽样,对特定参数的行为进行多次模拟。|

|数值数据(numerical data)|能够用(连续或离散)数字表示的信息。|

|

numpy

|用于数值数据处理的 Python 库,能高效执行向量和二维或多维数组的数学运算。|

|观察性研究(observational study)|受试者分配至处理组和对照组不由研究者掌控的研究。|

|配对检验(paired test)|当两组数据间存在一一对应关系时使用的检验手段:(1)每组数据点数量相等;(2)一组数据中的每个数据点仅与另一组中的一个数据点关联。|

|百分位数(percentile)|亦称 centile,大于或等于数据的

p%

的值,其中
1 <= p < 100

。|

|总体(population)|数据集的所有组成部分。|

|功效分析(power analysis)|计算检测特定规模效应所需最小样本量的过程。|

|功效(power)|与敏感度相同,用

1 - β

表示,其中
β

是第二类错误的概率。|

|概率密度函数(probability density function, PDF)|描述随机变量取特定值可能性的连续函数,随机变量在指定范围内取值的概率是该范围上概率密度函数的积分。|

|概率质量函数(probability mass function, PMF)|定义在实验或观察中取得给定数量事件概率的离散函数。|

|前瞻性研究(prospective study)|在研究过程中观察结果(如疾病的进展),并将其与其他因素(如潜在的风险或保护因素)关联的研究。|

|

pylab

|一个便捷的 Python 模块,将
matplotlib.pyplot

(用于绘图)和
numpy

(用于数学和数组操作)集成到一个命名空间中。|

|包(package)|包含一个或多个 Python 模块和一个

.ini

文件的目录。|

|分位数(quantile)|大于或等于数据的

p * 100%

的值,其中
0 < p <= 1

。|

|四分位数(quartile)|大于或等于数据的 25%、50%、75% 的值(第一、二、三四分位数),第二四分位数等同于中位数。|

|随机化(randomization)|通过将同质的受试者群体划分为对照组(不接受治疗)和治疗组,减少研究结果偏差的技术。|

|排序数据(ranked data)|数值代表数据排名的数据,即排序后数据序列中的位置,而非连续的数值。|

|正则表达式(regular expression)|定义搜索模式的字符序列,主要用于字符串的模式匹配,适用于 Unix、Python、Perl、Java、C++ 等多种编程语言。|

|残差(residual)|观测值与预测函数值之间的差距。|

|回顾性研究(retrospective study)|回顾历史,根据研究开始时已确定的结果,调查暴露于潜在风险或保护因素的情况。|

|样本(sample)|从总体中抽取的一个或多个观测值。|

|尺度(scale)|影响概率分布方差的参数。|

|

scipy

|基于
numpy

的科学计算 Python 库。|

|灵敏度(sensitivity)|真实阳性结果被准确识别的比例(例如患病者被正确诊断的比率)。|

|形状参数(shape parameter)|除了位置和尺度之外,影响概率分布形状的参数,较少使用。|

偏度(skewness)衡量分布不对称性的度量。
特异性(specificity)实际阴性结果被准确识别的比例(如健康人被准确诊断为未患病的百分比)。
标准差(standard deviation)方差的平方根。
标准误差(standard error)通常指均值的标准误差,即统计量方差的平方根。
处理(treatment)与因子相等。
第一类错误(type I error)当原假设正确时拒绝原假设的错误,其概率为假设检验的显著性水平,通常用
α
表示。
第二类错误(type II error)当备择假设正确时拒绝备择假设(未能拒绝原假设)的错误,其概率通常用
β
表示。
非配对检验(unpaired test)对两组独立数据实施的检验。
方差(variance)衡量一组数据分散程度的度量,数学上是数据与均值偏差平方的期望值:
Var(X) = E[(X - μ)^2]
。样本方差是总体方差的有偏估计,总体方差的最佳无偏估计为
s^2 = (1 / (n - 1)) * Σ(yi - y)^2
,称为(无偏)样本方差。

通过上述内容,我们详尽阐述了如何利用 Python 进行单组和多组数据的对比、分类数据的解析以及相关性和回归分析,并对关键的统计术语进行了阐释。这些方法和技术在实际的数据分析中有着广泛的应用,有助于我们更深入地理解数据、揭示模式并作出决策。

5. 代码示例总结
5.1 单组和两组数据比较代码总结
功能代码示例
单组数据均值检验
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
import scipy as sp
import os

def oneGroup():
    print('Single group of data')
    print('=========================================')
    data = np.array([5260, 5470, 5640, 6180, 6390, 6515,
                     6805, 7515, 7515, 8230, 8770], dtype=np.float)
    checkValue = 7725

    # 4.1.1. 正态性检验
    (_, p) = stats.normaltest(data)
    if p > 0.05:
        print('Data are distributed normally, p = {0}'.format(p))

    # 4.1.2. 单样本 t 检验
    t, prob = stats.ttest_1samp(data, checkValue)
    if prob < 0.05:
        print('With the one-sample t-test, {0:4.2f} is significantly different from the mean (p={1:5.3f}).'.format(checkValue, prob))
    else:
        print('No difference from reference value with onesample t-test.')

    # 4.1.3. Wilcoxon 检验
    (_, p) = stats.wilcoxon(data - checkValue)
    if p < 0.05:
        print('With the Wilcoxon test, {0:4.2f} is significantly different from the mean (p={1:5.3f}).'.format(checkValue, p))
    else:
        print('No difference from reference value with Wilcoxon rank sum test.')

if __name__ == '__main__':
    oneGroup()
两组数据均值比较
def twoGroups():
    print('Two groups of data')
    print('=========================================')
    data1 = [76., 101., 66., 72., 88., 82., 79., 73., 76., 85., 75., 64., 76., 81., 86.]
    data2 = [64., 65., 56., 62., 59., 76., 66., 82., 91., 57., 92., 80., 82., 67., 54.]

    # 正态性检验
    print('\n Normality test')
    print('--------------------------------------------------')
    for ii, data in enumerate((data1, data2)):
        (_, pval) = stats.normaltest(data)
        if pval > 0.05:
            print('Dataset # {0} is normally distributed'.format(ii))

    # 独立样本 t 检验
    print('\n T-test of independent samples')
    print('-------------------------------------------')
    t, pval = stats.ttest_ind(data1, data2)
    if pval < 0.05:
        print('With the T-test, data1 and data2 are significantly different (p = {0:5.3f})'.format(pval))
    else:
        print('No difference between data1 and data2 with T-test.')

    # Mann-Whitney 检验
    print('\n Mann-Whitney test')
    print('------------------------------------------------------')
    if np.int(sp.__version__.split('.')[1]) > 16:
        u, pval = stats.mannwhitneyu(data1, data2, alternative='two-sided')
    else:
        u, pval = stats.mannwhitneyu(data1, data2)
        pval *= 2
    if pval < 0.05:
        print('With the Mann-Whitney test, data1 and data2 are significantly different(p = {0:5.3f})'.format(pval))
    else:
        print('No difference between data1 and data2 with Mann-Whitney test.')

if __name__ == '__main__':
    twoGroups()
多组数据比较
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
import pandas as pd
from statsmodels.formula.api import ols
from statsmodels.stats.anova import anova_lm
from statsmodels.stats import multicomp
import xlrd

def get_ANOVA_data():
    inFile = 'Table 6.6 Plant experiment.xls'
    book = xlrd.open_workbook(inFile)
    sheet = book.sheet_by_index(0)
    treatment = sheet.col_values(4)
    weight = sheet.col_values(5)
    data = pd.DataFrame({'group': treatment[3:], 'weight': weight[3:]})
    return data

def do_ANOVA(data):
    print('ANOVA:')
    print('----------------------------------------------')
    model = ols('weight ~ C(group)', data).fit()
    anovaResults = anova_lm(model)
    print(anovaResults)
    if anovaResults['PR(>F)'][0] < 0.05:
        print('One of the groups is different.')

def compare_many(data):
    print('\n MultComp:')
    print('--------------------------------------')
    mc = multicomp.MultiComparison(data['weight'], data['group'])
    print(mc.tukeyhsd().summary())
    print(mc.groupsunique)

    res2 = mc.tukeyhsd()
    simple = False
    if simple:
        res2.plot_simultaneous()
    else:
        xvals = np.arange(3)
        plt.plot(xvals, res2.meandiffs, 'o')
        errors = np.ravel(np.diff(res2.confint) / 2)
        plt.errorbar(xvals, res2.meandiffs, yerr=errors, fmt='o')
        xlim = -0.5, 2.5
        plt.hlines(0, *xlim)
        plt.xlim(*xlim)
        pair_labels = mc.groupsunique[np.column_stack(res2._multicomp.pairindices)]
        plt.xticks(xvals, pair_labels)
        plt.title('Multiple Comparison of Means - Tukey HSD, FWER=0.05' + '\n Pairwise Mean Differences')
        plt.show()

def KruskalWallis(data):
    print('\n Kruskal-Wallis test')
    print('----------------------------------------------------')
    g_a = data['weight'][data['group'] == 'TreatmentA']
    g_b = data['weight'][data['group'] == 'TreatmentB']
    g_c = data['weight'][data['group'] == 'Control']
    h, p = stats.kruskal(g_c, g_a, g_b)
    print('Result from Kruskal-Wallis test: p = {0}'.format(p))

if __name__ == '__main__':
    data = get_ANOVA_data()
    do_ANOVA(data)
    compare_many(data)
    KruskalWallis(data)
5.2 分类数据的分析代码总结
功能代码示例
Fisher 精确检验
from scipy import stats

obs = [[3, 1], [1, 3]]
_, p = stats.fisher_exact(obs, alternative='greater')
print('\n--- A Lady Tasting Tea (Fisher Exact Test) ---')
print('The chance that the lady selects 3 or more cups correctly by chance is {0:5.3f}'.format(p))
Chi2 列联表检验
from scipy import stats

obs = [[36, 14], [30, 25]]
chi2, p, dof, expected = stats.chi2_contingency(obs)
print('--- Contingency Test ---')
if p < 0.05:
    print('p={0:6.4f}: the drug affects the heart rate.'.format(p))
else:
    print('p={0:6.4f}: the drug does NOT affect the heart rate.'.format(p))

obs2 = [[36, 14], [29, 26]]
chi2, p, dof, expected = stats.chi2_contingency(obs2)
chi2, p2, dof, expected = stats.chi2_contingency(obs2, correction=False)
print('If the response in 1 non - treated person were different, \n we would get p={0:6.4f} with Yates correction, and p={1:6.4f} without.'.format(p, p2))
Chi2 单向检验
from scipy import stats

obs = [4, 6, 14, 10, 16]
_, p = stats.chisquare(obs)
print('\n--- Chi2-oneway ---')
if p < 0.05:
    print('The difference in opinion between the different age groups is significant (p={0:6.4f})'.format(p))
else:
    print('The difference in opinion between the different age groups is NOT significant (p={0:6.4f})'.format(p))
print('DOF={0:3d}'.format(len(obs) - 1))
McNemar 检验
from scipy import stats
from statsmodels.sandbox.stats.runs import mcnemar

obs = [[19, 1], [6, 14]]
obs2 = [[20, 0], [6, 14]]
_, p = mcnemar(obs)
_, p2 = mcnemar(obs2)
print('\n--- McNemar Test ---')
if p < 0.05:
    print('The results from the neurologist are significantly different from the questionnaire (p={0:5.3f}).'.format(p))
else:
    print('The results from the neurologist are NOT significantly different from the questionnaire (p={0:5.3f}).'.format(p))
if (p < 0.05 == p2 < 0.05):
    print('The results would NOT change if the expert had diagnosed all "sane" people correctly.')
else:
    print('The results would change if the expert had diagnosed all "sane" people correctly.')
5.3 相关性和回归分析代码总结
功能代码示例
相关性分析
import numpy as np
import pandas as pd
from scipy import stats
import matplotlib.pyplot as plt
import seaborn as sns

def getModelData(show=True):
    in_file = 'AvgTemp.xls'
    xls = pd.ExcelFile(in_file)
    data = xls.parse('Tabelle1')
    if show:
        data.plot('year', 'AvgTmp')
        plt.xlabel('Year')
        plt.ylabel('Average Temperature')
        plt.show()
    return data

if __name__ == '__main__':
    data = getModelData()
    print('Pearson correlation coefficient: {0:5.3f}'.format(data['year'].corr(data['AvgTmp'], method='pearson')))
    print('Spearman correlation coefficient: {0:5.3f}'.format(data['year'].corr(data['AvgTmp'], method='spearman')))
    print('Kendall tau: {0:5.3f}'.format(data['year'].corr(data['AvgTmp'], method='kendall')))
回归分析
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
import seaborn as sns
import statsmodels.formula.api as sm
from S11_correlation import getModelData

if __name__ == '__main__':
    data = getModelData(show=False)
    model = sm.ols('AvgTmp ~ year', data)
    results = model.fit()
    print(results.summary())
    sns.lmplot('year', 'AvgTmp', data)
    plt.show()
    ci = results.conf_int()
    if np.prod(ci.loc['year']) > 0:
        print('The slope is significant')
正态性检验
from scipy import stats
import matplotlib.pyplot as plt
import statsmodels.formula.api as sm
import seaborn as sns
from S11_correlation import getModelData

if __name__ == '__main__':
    data = getModelData(show=False)
    model = sm.ols('AvgTmp ~ year', data)
    results = model.fit()
    res_data = results.resid
    stats.probplot(res_data, plot=plt)
    plt.show()
    _, pVal = stats.normaltest(res_data)
    if pVal < 0.05:
        print('WARNING: The data are not normally distributed (p = {0})'.format(pVal))
    else:
        print('Data are normally distributed.')
6. 实际应用场景
6.1 医学研究

在医学研究领域,我们可以运用上述统计方法来评估药物的疗效、疾病的风险因素等。例如,使用两组数据比较的方法来对比不同药物治疗某疾病的效果;使用分类数据分析的方法来探究某疾病与患者的性别、年龄等因素的关系。

6.2 市场调研

在市场调研中,我们可以采用相关性和回归分析来探讨消费者的购买行为与产品价格、广告投入等因素的关系。例如,通过分析历史销售数据,构建回归模型来预测未来的销售额。

6.3 工业生产

在工业生产中,我们可以利用多组数据比较的方法来对比不同生产工艺的效率和质量。例如,通过对不同生产线的产品质量数据进行 ANOVA 分析,找到最优的生产工艺。

7. 总结

本文详尽介绍了使用 Python 进行统计分析的方法,涵盖单组和两组数据比较、分类数据分析以及相关性和回归分析。同时,对一些关键的统计术语进行了说明,帮助读者更好地理解这些方法。通过实际的代码示例和应用场景,展示了这些方法在不同领域的应用。在实际数据分析中,我们可以根据数据的性质和问题的需求,选择适当的统计方法进行分析,从而更有效地理解数据、揭示规律并作出决策。

在使用这些方法时,需注意以下几点:

  1. 数据质量:确保数据的精确性和完整性,防止因数据问题影响分析结果的准确性。
  2. 方法选择:依据数据的特点和问题的需求,选取适合的统计方法。例如,对于符合正态分布的数据,可使用参数检验方法;对于不符合正态分布的数据,可使用非参数检验方法。
  3. 结果解释:正确解读统计分析的结果,避免过度解读或误读。例如,在假设检验中,需明确原假设和备择假设的意义,以及 p 值的作用。

通过持续的学习和实践,我们可以熟练掌握这些统计分析方法,提升数据分析的技能和水平。

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

栏目导航
热门文章
推荐文章

说点什么

分享

扫码加好友,拉您进群
各岗位、行业、专业交流群