OSEMN(Obtain, Scrub, Explore, Model, iNterpret)是一种常用的数据分析方法论,包括数据获取、数据清洗、数据探索、建模和解释等步骤。OSEMN方法论强调了数据分析过程中数据质量和数据探索的重要性。
数理统计分为如下两类:
描述性统计所提取统计的信息,称为统计量,主要包括以下几个方面:
集中趋势分析
均值
中位数
众数
分位数
离散程度分析
极差
方差
标准差
分布形状
import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from sklearn.datasets import load_iris import warnings 设置seaborn绘图样式与字体规模 sns.set(style="darkgrid", font_scale=1.2) plt.rcParams["font.family"] = "SimHei" # 设置中文字体 plt.rcParams["axes.unicode_minus"] = False # 是否使用Unicode字符集中的负号 warnings.filterwarnings("ignore") # 忽略警告信息 iris = load_iris() # 加载鸢尾花数据集 print(iris.data.shape) # NumPy 数组 (150, 4) print(iris.target.shape) # NumPy 数组 (150, ) 每朵鸢尾花对应的类别,取值为0,1,2 print(iris.feature_names) # 特征列的名称 print(iris.target_names) # 鸢尾花类别的名称,即数值0,1,2分别对应的类别 合并数据 data = np.concatenate([iris.data, iris.target.reshape(-1, 1)], axis=1) # 横向拼接,-1的作用是自动计算行 data = pd.DataFrame(data, columns=["sepal_length", "sepal_width", "petal_length", "petal_width", "type"]) data.sample(10) # 随机抽样 frequency = data["type"].value_counts() # 计算类别出现的频数 print(frequency) percentage = frequency * 100 / len(data) # 计算类别出现的频率 print(percentage) sns.countplot(x="type", data=data) # 绘制type列不同取值出现的次数 plt.show()
mean = data["sepal_length"].mean() # 花萼长度的均值 median = data["sepal_length"].median() # 中位数 s = data["sepal_length"].mode() # mode方法返回Series类型 mode = s.iloc[0] # 众数 print(mean, median, mode) sns.distplot(data["sepal_length"]) # 绘制数据的发布,直方图 + 密度图 绘制垂直线 plt.axvline(mean, ls="-", color="r", label="均值") plt.axvline(median, ls="-", color="g", label="中值") plt.axvline(mode, ls="-", color="indigo", label="众数") plt.legend() x = [1, 3, 10, 15, 18, 20, 23, 40] print(np.quantile(x, q=[0.25, 0.5, 0.75])) # 计算分位数 print(np.percentile(x, q=[25, 50, 75])) s = pd.Series(x) print(s.describe()) # pandas中计算分位数 print(s.describe(percentiles=[0.25, 0.9]))
sub = np.ptp(data["sepal_length"]) # 极差 var = data["sepal_length"].var() # 方差 std = data["sepal_length"].std() # 标准差 print(sub, var, std) plt.figure(figsize=(15, 4)) # 设置图形大小,宽*高,单位为英寸 plt.ylim(-0.5, 1.5) plt.plot(data["petal_length"], np.zeros(len(data)), linestyle="", marker="o", markersize=10, color="g", label="花瓣长度") plt.plot(data["petal_width"], np.ones(len(data)), ls="", marker="o", ms=10, color="r", label="花瓣宽度") plt.axvline(data["petal_length"].mean(), ls="--", color="g", label="花瓣长度均值") plt.axvline(data["petal_width"].mean(), ls="--", color="r", label="花瓣宽度均值") plt.legend()
## 构造左偏分布数据 t1 = np.random.randint(1, 11, size=100) t2 = np.random.randint(11, 21, size=500) t3 = np.concatenate([t1, t2]) left_skew = pd.Series(t3) 构造右偏分布数据 t1 = np.random.randint(1, 11, size=500) t2 = np.random.randint(11, 21, size=100) t3 = np.concatenate([t1, t2]) right_skew = pd.Series(t3) print(left_skew.skew(), right_skew.skew()) 绘制核密度图 sns.kdeplot(left_skew, shade=True, label="左偏") sns.kdeplot(right_skew, shade=True, label="右偏") plt.legend() 标准正态分布 standard_normal = pd.Series(np.random.normal(0, 1, size=10000)) print("标准正态分布峰度:", standard_normal.kurt(), "标准差:", standard_normal.std()) sns.kdeplot(standard_normal, label="标准正态分布") sns.kdeplot(data["sepal_width"], label="花萼宽度") sns.kdeplot(data["petal_length"], label="花瓣长度") plt.legend()
总体的参数往往是未知的,为了获取总体的参数,就需要通过样本统计量来估计总体参数。
import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from sklearn.datasets import load_iris import warnings sns.set(style="darkgrid", font_scale=1.2) plt.rcParams["font.family"] = "SimHei" plt.rcParams["axes.unicode_minus"] = False warnings.filterwarnings("ignore") iris = load_iris() data = np.concatenate([iris.data, iris.target.reshape(-1, 1)], axis=1) data = pd.DataFrame(data, columns=["sepal_length", "sepal_width", "petal_length", "petal_width", "type"]) print(data["petal_length"].mean())
点估计容易受到随机抽样的影响,可能无法保证结论的准确性。但是,样本来自于总体,样本还是能够体现出总体的一些特征的。
区间估计使用一个置信区间与置信度,表示总体参数有多少可能(置信度)会在该范围(置信区间)内。
样本均值分布的标准差,称为标准误差,简称标准误。
根据中心极限定理,如果多次抽样(总体的均值为μ,方差为σ*σ*),则样本均值构成的正态分布,满足样本均值~N(μ, σσ/n),如果只对总体进行一次抽样,则该样本的均值有95%的概率会在(μ-2σ, μ+2σ)范围内,仅有5%的概率会在(μ-2σ, μ+2σ)范围外。根据小概率事件(很小的概率在一次抽样中基本不会发生),如果抽样的样本均值在(μ-2σ, μ+2σ)之外,就可以认为,本次抽样来自的总体,该总体的均值并非是我们所期望的均值。
通常,以2倍标准差作为判依据,即以样本均值为中心,正负2倍标准差构成的区间,就是置信区间。而2倍标准差包含了95%的数据,因此,此时的置信度为95%。换言之,有95%的信心认为总体的均值会在置信区间之内。
a = np.array([0.497, 0.506, 0.518, 0.524, 0.498, 0.511, 0.520, 0.515, 0.512]) mean, std = 0.5, 0.015 # 总体均值与标准差 sample_mean = a.mean() # 样本均值 se = std / np.sqrt(len(a)) # 标准误 left, right = sample_mean - 1.96 * se, sample_mean + 1.96 * se print(f"置信区间:({left:.3f}, {right:.3f})") plt.plot(mean, 0, marker="*", color="orange", ms=15, label="总体均值") plt.plot(sample_mean, 0, marker="o", color="r", label="样本均值") plt.hlines(0, xmin=left, xmax=right, color="b", label="置信区间") plt.axvline(left, 0.4, 0.6, color="r", ls="--", label="左边界") plt.axvline(right, 0.4, 0.6, color="g", ls="--", label="右边界") plt.legend()
设置原假设与备择假设
Z检验用于正态总体均值的检验,即用来检验总体的均值(末知)是否与假设的均值相同。
from scipy import stats a = np.array([0.497, 0.506, 0.518, 0.524, 0.498, 0.511, 0.520, 0.515, 0.512]) mean, std = 0.5, 0.015 # 总体均值与标准差 sample_mean = a.mean() # 样本均值 se = std / np.sqrt(len(a)) # 标准误 Z = (sample_mean - mean) / se # Z统计量 print("统计量Z:", Z) 计算P值 sf函数,根据参数指定的统计量,返回该统计量与右侧图像围成的面积值 实际上,P值就是通过概率密度函数计算出来的面积,即概率值 P = 2 * stats.norm.sf(abs(Z)) print("P-Value值:", P)
由结果可知,Z值偏离超过了2倍的标准差,P值也就小于0.05。因此,在显著性水平α=0.05下,P<α,故拒绝原假设,接受备择假设,即认为机器运作是不正常的。
右边假设检验的拒绝域在正态分布的右侧区域。
原假设:μ≤μ0=0.5kg(机器运作正常)
备择假设:μ>μ0≠0.5kg(机器运作不正常)
P = stats.norm.sf(Z) print("P-Value值:", P)
P<α,拒绝原假设,认为机器运作是不正常的。
左边假设检验的拒绝域在正态分布的左侧区域。
原假设:μ≥μ0=0.5kg(机器运作正常)
备择假设:μ<μ0≠0.5kg(机器运作不正常)
P = stats.norm.cdf(Z) print("P-Value值:", P)
P>α,维持原假设,认为机器运作是正常的。
接受H0拒绝H0H0为真正确I类错误(α错误,去真错误)H0为假II类错误(β错误,取伪错误)正确
与Z检验的应用场景类似,t检验也用于正态总体均值的检验。只不过,t检验的正态总体,标准差是未知的。
t检验分为三种类型:
单样本t检验前提条件为:
总体方差(标准差)末知
mean = data["petal_length"].mean() std = data["petal_length"].std() t = (mean - 3.5) / (std / np.sqrt(len(data))) # t统计量 print("t统计量:", t) P = 2 * stats.t.sf(abs(t), df=len(data["petal_length"]) - 1) print("P-Value值:", P) 此外,也可通过scipy提供的相关方法来进行t检验的计算,无需自行计算 stats.ttest_1samp(data["petal_length"], 3.5)
两独立样本t检验用于检验两个正态总体的均值是否相同,其前提条件为:
由于方差是否齐性(相同),会影响t统计量的计算。因此,在进行两独立样本t检验时,首先需要进行方差齐性检验。可以通过Levene检验来判断两个正态总体的方差是否相同。
## A,B两个学校的学生数据 school_A = np.array([169.7, 163.1, 179.0, 163.4, 180.2, 160.9, 177.3, 160.7, 169.9, 163.4]) school_B = np.array([163.6, 180.0, 171.8, 174.7, 164.3, 173.9, 167.0, 162.9, 164.2, 171.6]) print(school_A.mean(), school_B.mean()) 使用levene检验判断两个样本背后的总体,其方差是否一致 stats.levene(school_A, school_B)
P>0.05,因此可以认为两个总体的方差是相同的。然后,就可以使用两独立样本t检验,来验证两个正态总体的均值是否相同。
stats.ttest_ind(school_A, school_B, equal_var=False)
P>0.05,因此维持原假设,认为两个正态总体的均值是相同的,即A与B两个学校的平均身高相同。
两配对样本t检验,是同一组受试者产生两组数据,然后,验证两组数据是否存在显著性差异的方式。两组数据可以是:
两配对样本t检验的前提条件为 :
配对样本差值独立
配对样本差值服从正态分布
总体标准差末知
train_before = np.array([98.8, 92.0, 94.9, 101.2, 99.3, 85.1, 94.8, 89.2, 89.5, 92.1]) 培训后体重数据 train_after = np.array([88.4, 92.4, 90.3, 88.4, 89.3, 89.0, 92.5, 87.4, 88.9, 85.4]) 两配对样本t检验(双边检验) stats.ttest_rel(train_before, train_after)
P<0.05,拒绝原假设,认为体重在培训前跟培训后是不同的。
如果没有充足的证据证明减肥有效,则应该按照减肥无效处理。则:
原假设:D≤0(减肥无效)
备择假设:D>0(减肥有效)
sta = stats.ttest_rel(train_before, train_after).statistic # 获取统计量 P = stats.t.sf(sta, df=len(train_before) - 1) print(P)
P<0.05,拒绝原假设,认为减肥有效。
卡方检验用于检测变量的理论频数与实际频数是否一致。
卡方检验可以分为两个类别 :
关于卡方检验,说明如下 :
卡方检验(单个变量)的前提条件为 :
举例:某手机在一段时间内,销量为200,各种颜色销量如下表所示: 红色绿色黄色紫色白色4350243152 请问该款手机的颜色对销售是否会造成影响?
o = [43, 50, 24, 31, 52] e = [40, 40, 40, 40, 40] stats.chisquare(f_obs=o, f_exp=e)
P<0.05,拒绝原假设,认为理论频数与实际频数不一致,得出结论:手机颜色对销售确实造成了影响。
举例:某手机在一段时间内,每种颜色与性别的销量如下表所示: 红色绿色黄色紫色白色男4350243152女3842302945 请问该款手机的购买用户中,性别与手机颜色是否具有关联?
根据随机变量独立性的定义,如果两个随机变量A与B是独立的,则有:
P(AB) = P(A)*P(B)
因此,可以根据该定义来计算在性别与颜色两个变量独立的情况下,每个变量取值的期望概率(理论概率。例如,计算性别为男,颜色为红色为例。
P(A=男, B=红色) = P(A=男) * P(B=红色) =(43 + 50 + 24 + 31 + 52) / 384 * (43 + 38) / 384 =0.52083 * 0.2109 =0.10986328125
有了期望概率,就可以很容易计算每个取值的期望频数: Expected(A=男, B=红色) = count * P(A=男, B=红色) =384 *0.10986328125 =42.1875
observed = [[43, 50, 24, 31, 52], [38, 42, 30, 29, 45]] stats.chi2_contingency(observed)
P>0.05,维持原假设,认为理论频数与实际频数一致(意味着两个变量是独立的),得出结论:性别对手机颜色没有影响,他们之间没有关系。
本文作者:a
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!