数据分析师一定要掌握的基础——描述性统计分析

以下博客内容讲解了描述性统计分析的所有知识点,以及利用鸢尾花数据集的分析加强对各个统计量的理解。

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 np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_iris
import 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 stats
stats.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中四分位值的计算方式如下:

  1. 首先,计算四分位的位置。
    在这里插入图片描述
    其中,位置索引index从0开始,n为数组中元素的个数。
    假设现在n=5,我们来计算下四分位值分别是多少?
    在这里插入图片描述
  2. 根据位置计算四分位值。
    在这里插入图片描述
    如果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.25
q2_index = (n - 1) * 0.5
q3_index = (n - 1) * 0.75
print(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.25
q2_index = (n - 1) * 0.5
q3_index = (n - 1) * 0.75
print(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] * weight
print(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实现。
发布了58 篇原创文章 · 获赞 274 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_39783601/article/details/105225491
今日推荐