申明:文章内容是作者自己的学习笔记,教学来源是开课吧讲师梁勇老师。
以下博客内容讲解了描述性统计分析的所有知识点,以及利用鸢尾花数据集的分析加强对各个统计量的理解。
数理统计基础-描述性统计分析
1、数理统计基础2、描述性统计分析概述(1)概念(2)变量的类型 3、统计量(1)频数与频率a. 频数b. 频率 (2)集中趋势a. 均值b. 中位数c. 众数d. 分位数 (3)离散程度a. 极差b. 方差c.标准差 (4)分布形状a. 偏度b. 峰度 4、总结1、数理统计基础
数理统计,以概率论为基础,研究大量随机现象的统计规律性。数理统计分为如下两类:
描述统计推断统计
数理统计在数据分析领域具有非常重要的地位。
2、描述性统计分析概述
(1)概念
什么是描述性统计分析?
描述性统计分析,就是从总体数据中提取变量的主要信息(总和、均值等),从而从总体层面上,对数据进行统计性描述。在统计的过程中,通常会配合绘制相关的统计图来进行辅助。
描述性统计所提取统计的信息,我们称为**统计量
**,主要包括以下几个方面:
频数与频率- 频数- 频率
集中趋势分析- 均值- 中位数- 众数- 分位数
离散程度分析- 极差- 方差- 标准差
分布现状- 偏度- 峰度
(2)变量的类型
从统计学角度看,变量可以分为以下两种类型。
变量的类型:
类别变量(变量的值是一个具体的类别)
无序类别变量(名义变量)
(变量的各个取值之间没有大小顺序之分)有序类别变量(等级变量)
(变量值之间有大小之分)
数值变量(具体的一个数值)
连续变量(区间之内取任意一个值)离散变量(不能取区间内的任意值,只能取整数值)
3、统计量
(1)频数与频率
数据的频数与频率统计适用于类别变量。
a. 频数
频数,指数据中类别变量每个不同取值出现的次数。
例如:我们去超市买苹果,买了5次,这个就是频数。
b. 频率
频率,指每个类别变量的频数与总次数的比值,通常采用百分数表示。
例如:我们取超市买苹果5次,总公去了10次,那么5/10(50%)就是频率。
我们以鸢尾花(iris)数据集进行分析:
鸢尾花数据集中包含150行4列3类数据,每类各50个数据。
每条记录都有 4 项特征:花萼长度、花萼宽度、花瓣长度、花瓣宽度,可以通过这4个特征预测鸢尾花卉属于(iris-setosa, iris-versicolour, iris-virginica)中的哪一品种。
》》》导入库、设置图形样式等:
import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport seaborn as snsfrom sklearn.datasets import load_irisimport warnings# 设置seaborn绘图的样式。# darkgrid 设置成暗色的网格的形式sns.set(style="darkgrid")# 设置字体plt.rcParams["font.family"] = "SimHei"# 对符号的支持plt.rcParams["axes.unicode_minus"] = False# 忽略警告信息。warnings.filterwarnings("ignore")
我们来加载数据查看下:
# 加载鸢尾花数据集。iris = load_iris()display(iris)
data 就是鸢尾花的数据,我们这里只展示部分数据:
target 就是鸢尾花的类别,类别为0,1,2
三种鸢尾花的类别分别是什么呢?
分类是山鸢尾花(Iris Setosa)、变色鸢尾花(Iris Versicolor)、维吉尼亚鸢尾花(Iris Virginica)。
接着我们看下具体的数据:
因为数据太多,我们只利用切片查看前10行数据,类别也查看前10行。
# iris.data:鸢尾花数据集。# iris.target:每朵鸢尾花对应的类别。(取值为0,1,2)display(iris.data[:10], iris.target[:10])# iris.feature_names:特征列的名称。# iris.target_names:鸢尾花类别的名称。display(iris.feature_names, iris.target_names)
4列(特征列)数据分别代表:花萼长度、花萼宽度、花瓣长度、花瓣宽度。
接下来我们进行简单的分析
首先我们需要把鸢尾花的数据和类别拼接到一起:
# 将鸢尾花数据与对应的类型合并,组合成完整的记录。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"])data.sample(10)
因为鸢尾花的数据iris.data为二维数组,但是类别iris.target为一维数组,此时我们需要通过reshape
来将一维数组转换为二维数组。
axis=1 表示纵向,此时为纵向拼接。
我们以类型(type)列为例,来计算鸢尾花每个类别的频数和频率。
# 计算鸢尾花数据中,每个类别出现的频数。frequency = data["type"].value_counts()display(frequency)# 计算每个类别出现的频率,通常使用百分比表示。percentage = frequency * 100 / len(data)display(percentage)
len(data) 鸢尾花数据的总长度;
因为要用百分比表示所以要乘以100;
value_counts() 计算个数。
从结果可知,类别中0,1,2分别出现了50次,他们的频率分别为33.333333
我们用柱形图来看下类别的个数情况:
(2)集中趋势
a. 均值
均值,即平均值,其为一组数据的总和除以数据的个数。
b. 中位数
将一组数据升序排列,位于该组数据最中间位置的值,就是中位数,如果数据个数为偶数,则取中间两个数值的均值。
c. 众数
一组数据中出现次数最多的值。
关于三者,说明如下:
三者的关系如下图所示:
什么是正态分布(对称分布)?
正态分布是以均值作为对称的一种分布形式。
左偏分布:
存在少数的极小值。
右偏分布:
存在少数的极大值。
怎么区分左偏分布和右偏分布?
从图形中间切一刀,哪边面积少就是什么分布。
例如:下面图形右边的面积少,所以就是右偏分布
接下来我们以鸢尾花长度为例,计算其集中趋势:
# 计算花萼长度的均值。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)
mean()
均值,median()
中位数,mode()
众数
结果:
我们可以看到结果中鸢尾花的花萼长度列,均值和中位数几乎相等,我们猜想该数据应该是对称分布的,符合正态分布,这也应了自然界的数据都符合正态分布的说法。
我们也可以使用scipy中的stats模块来求一组数据的众数。
from scipy import statsstats.mode(data["sepal_length"]).mode
结果:array([5.]),可以看到和Series算出来的众数是一样的。
接下来把上面的数据进行可视化:
# 绘制数据的分布(直方图 + 密度图)。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()
distplot
核密度图
d. 分位数
把数据集分成若干个区间,分为几就为几分位数。
先排序再分位,分位大致相等的若干区间。
给定一组数据,假设存放在数组中,我们要如何计算其四分位值呢?首先要明确一点,四分位值未必一定等同于数组中的某个元素。
在Python中四分位值的计算方式如下:
首先,计算四分位的位置。
其中,位置索引index从0开始,n为数组中元素的个数。
假设现在n=5,我们来计算下四分位值分别是多少?
根据位置计算四分位值。
如果n-1不能被4整除又该怎么办呢?
假设有这么一组数据:
n=6,四分位处的值会得出一个小数,这时候我们就不能用索引的方式直接计算。
Q1结果等于5 * 1/4 = 1.25,1.25是介于1和2之间
但更接近于索引1,也就离12这个数更近,说明12这个数的权重更高。
怎么计算权重呢?
用1减去小数部分,就是左边的权重,小数部分本身就是右边的权重。
用1-0.25=0.75,0.75就是12的权重,那么13的权重就是0.25。
当我们得到权重之后,怎么计算四分位数呢,例如计算1/4(Q1):
Q1=12 * 0.75+13 * 0.25,结果就是1/4位数。
剩下Q2、Q3是类似的方法计算即可。
index为整数的情况
我们首先来计算四分位的位置:
x = np.arange(10, 19) #9个数n = len(x)# 计算四分位的索引(index)。q1_index = (n - 1) * 0.25q2_index = (n - 1) * 0.5q3_index = (n - 1) * 0.75print(q1_index, q2_index, q3_index)
结果:2.0 4.0 6.0
拿着2.0 4.0 6.0的索引值去找对应的四分位值即可。但是因为索引值没有小数,需要把0去掉转为整数类型:
# 将index转换成整数类型。index = np.array([q1_index, q2_index, q3_index]).astype(np.int32)print(x[index])
结果:[12 14 16],即1/4位,中位,3/4位数。
可视化呈现:
plt.figure(figsize=(15, 4))plt.xticks(x)plt.plot(x, np.zeros(len(x)), ls="", marker="D", ms=15, label="元素值")plt.plot(x[index], np.zeros(len(index)), ls="", marker="X", ms=15, label="四分位值")plt.legend()
index不是整数的情况
当index不是整数时,我们使用最近位置的两个整数,加权计算来得到四分位的位置。每个整数的权重为距离的反比。
x = np.arange(10, 20)n = len(x)q1_index = (n - 1) * 0.25q2_index = (n - 1) * 0.5q3_index = (n - 1) * 0.75print(q1_index, q2_index, q3_index)
结果:2.25 4.5 6.75
可以看到计算结果不是整数
我们使用该值临近的两个整数来计算四分位值。
index = np.array([q1_index, q2_index, q3_index])# 计算左边元素的值。left = np.floor(index).astype(np.int32)# 计算右边元素的值。right = np.ceil(index).astype(np.int32)# 获取index的小数部分weight与整数部分_ 。weight, _ = np.modf(index)# 根据左右两边的整数,加权计算四分位数的值。权重与距离成反比。q = x[left] * (1 - weight) + x[right] * weightprint(q)
结果:[12.25 14.5 16.75],1/4分位12.25,2/4分位14.5,3/4分位16.75
weight, _ = np.modf(index)
中下划线的解释:
Python中我们对于不使用的变量,习惯用 _ 来命名变量。
也就是在2.25 4.5 6.75中,2,4,6整数部分我们不用,所以定义成下划线即可。
可视化呈现:
plt.figure(figsize=(15, 4))plt.xticks(x)plt.plot(x, np.zeros(len(x)), ls="", marker="D", ms=15, label="元素值")plt.plot(q, np.zeros(len(q)), ls="", marker="X", ms=15, label="四分位值")for v in q:plt.text(v, 0.01, s=v, fontsize=15)plt.legend()
结论:
四分位值不一定出现在我们数据的元素中。
我们刚才自行计算了每个四分位的值,但是,其实在Python中,Numpy与Pandas提供了相关的方法,无需我们自行计算。
Numpy中计算四分位数:
x = [1, 3, 10, 15, 18, 20, 23, 40]# quantile与percentile都可以计算分位数,不同的是,quantile方法,# q(要计算的分位数)的取值范围为[0, 1],而percentile方法,q的# 取值范围为[0, 100]。print(np.quantile(x, q=[0.25, 0.5, 0.75]))print(np.percentile(x, q=[25, 50, 75]))
结果:
[ 8.25 16.5 20.75]
[ 8.25 16.5 20.75]
Numpy 中quantile与percentile计算四分位数的区别:
quantile方法, q(要计算的分位数)的取值范围为[0, 1]
percentile方法,q的取值范围为[0, 100]。
Pandas中计算四分位数:
x = [1, 3, 10, 15, 18, 20, 21, 23, 40]s = pd.Series(x)print(s.describe())
在上面的结果中,我们如何将四分之一分位的值提取出来呢?
s.describe()[4]s.describe()['25%']s.describe().iloc[4]s.describe().loc['25%']s.describe().ix[4]s.describe().ix['25%']
建议使用 s.describe().iloc[4] 和 s.describe().loc[‘25%’] 这两种方式取值,因为更具有针对性,分别是位置索引和标签索引取值,不容易产生错误。
默认情况下,describe 方法会统计各个四分位的值,我们可以通过percentiles参数来自定义需要统计的分为(百分位)。
(3)离散程度
a. 极差
极差指一组数据中,最大值和最小值之差。
b. 方差
方差体现的是一组数据中,每个元素与均值偏离的大小。
c.标准差
标准差为方差的开方。
关于极差、方差和标准差:
我们以花萼长度来看下离散程度:
# 计算极差。sub = data["sepal_length"].max() - data["sepal_length"].min()# 计算方差。var = data["sepal_length"].var()# 计算标准差。std = data["sepal_length"].std()print(sub, var, std)
var()
方差、std()
标准差
结果:
3.6000000000000005 0.6856935123042505 0.8280661279778629
可视化显示:
plt.figure(figsize=(15, 4))plt.ylim(-0.5, 1.5)plt.plot(data["petal_length"], np.zeros(len(data)), ls="", marker="o", ms=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()
从图形可以看出:
花瓣宽度(红色的)围绕均值更加集中,而花瓣长度(绿色的)围绕均值更加分散。
从方差或者标准差的角度绿色的方差就会大,而红色的方差就会小。
(4)分布形状
a. 偏度
偏度是统计数据分布倾斜方向和程度的度量,是统计数据分布非对称程度的数学特征。
# 构造左偏分布数据。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()
偏度结果:
-0.858626159687255 0.8159924321369632
核密度(概率密度分布)图:
有极大或极小值时,也就是出现左偏或者右偏分布数据的时候,不适用使用均值,因为均值会被异常值所影响,这个时候可以使用中位数或者众数说明,又或者我们提前把异常值处理掉再使用也可以。
b. 峰度
峰度是描述总体中所有取值分布形态陡缓程度的统计量。可以将峰度理解为数据分布的高矮程度。峰度的比较是相对于标准正态分布的。
standard_normal = pd.Series(np.random.normal(0, 1, size=10000))print("标准正态分布峰度:", standard_normal.kurt(), "标准差:", standard_normal.std())print("花萼宽度峰度:", data["sepal_width"].kurt(), "标准差:", data["sepal_width"].std())print("花瓣长度峰度:", data["petal_length"].kurt(), "标准差:", data["petal_length"].std())sns.kdeplot(standard_normal, label="标准正态分布")sns.kdeplot(data["sepal_width"], label="花萼宽度")sns.kdeplot(data["petal_length"], label="花瓣长度")
结果:
和标准正态分布比较:
峰度越大,标准差越小并且小于标准正态分布的标准差,其图形月窄。
峰度越小,标准差越大并且大于标准正态分布的标准差,其图形越宽。
4、总结
描述性统计分析的概念和应用。频率与频数的使用。集中趋势与离散程度。数据分析形状之偏度和峰度。各种统计量使用Python实现。