數據分析師一定要掌握的基礎——描述性統計分析

申明:文章內容是作者自己的學習筆記,教學來源是開課吧講師梁勇老師。

以下博客內容講解了描述性統計分析的所有知識點,以及利用鳶尾花數據集的分析加強對各個統計量的理解。

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實現。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章