數據挖掘之統計學基礎(4):【實踐】數據分佈-Python實戰

import numpy as np
import pandas as pd
import time

import matplotlib as mpl
import matplotlib.pyplot as plt

%matplotlib inline

plt.style.use('ggplot')
plt.rcParams['figure.figsize'] = (18.0, 10.0)

pd.set_option('display.float_format', lambda x: '%.4f' % x)
pd.set_option('display.max_rows', 200)
pd.set_option('display.max_columns', 200)

1. 使用 Python 驗證數據集中的體溫是否符合正態分佈。

- 數據集地址:http://jse.amstat.org/datasets/normtemp.dat.txt
- 數據集描述:總共只有三列:體溫、性別、心率
- 數據集詳細描述:Journal of Statistics Education, V4N2:Shoemaker

加載數據

# filename = 'http://jse.amstat.org/datasets/normtemp.dat.txt'
filename = 'normtemp.dat.txt'

feature_name_list = [
    '體溫',
    '性別',
    '心率',
]

df = pd.read_csv(filename, sep='\s+', header=None, skiprows=1, names=feature_name_list)

print('df shape={}'.format(df.shape))
print('df info={}'.format(df.info()))
print('df describe={}'.format(df.describe()))     
display(df.head())

df shape=(130, 3)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 130 entries, 0 to 129
Data columns (total 3 columns):
體溫    130 non-null float64
性別    130 non-null int64
心率    130 non-null int64
dtypes: float64(1), int64(2)
memory usage: 3.1 KB
df info=None
df describe=            體溫       性別       心率
count 130.0000 130.0000 130.0000
mean   98.2492   1.5000  73.7615
std     0.7332   0.5019   7.0621
min    96.3000   1.0000  57.0000
25%    97.8000   1.0000  69.0000
50%    98.3000   1.5000  74.0000
75%    98.7000   2.0000  79.0000
max   100.8000   2.0000  89.0000
體溫 性別 心率
0 96.3000 1 70
1 96.7000 1 71
2 96.9000 1 74
3 97.0000 1 80
4 97.1000 1 73
df['體溫'].hist(bins=130)

<matplotlib.axes._subplots.AxesSubplot at 0x122fdd5f8>

在這裏插入圖片描述

import seaborn as sns 
sns.set_palette("hls")
sns.distplot(df['體溫'], bins=130, kde=True)
plt.show()

/Users/jliang/anaconda3/envs/py36/lib/python3.6/site-packages/scipy/stats/stats.py:1633: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.
  return np.add.reduce(sorted[indexer] * weights, axis=axis) / sumval

在這裏插入圖片描述

檢驗溫度數據是否符合正態分佈

  • 頻數分佈有正態分佈和偏態分佈之分。正態分佈是指多數頻數集中在中央位置,兩端的頻數分佈大致對稱。
  • 偏態分佈是指頻數分佈不對稱,集中位置偏向一側。若集中位置偏向數值小的一側,稱爲正偏態分佈;集中位置偏向數值大的一側,稱爲負偏態分佈。
  • 如果頻數分佈的高峯向左偏移,長尾向右側延伸稱爲正偏態分佈,也稱右偏態分佈;同樣的,如果頻數分佈的高峯向右偏移,長尾向左延伸則成爲負偏態分佈,也稱左偏態分佈。

方法一:根據峯度係數和偏度係數判斷

  • 峯度係數是用於判定分佈是不是太尖或太平;
  • 偏度係數用於判定偏左還是偏右;

利用變量的偏度和峯度進行正態性檢驗時,可以分別計算偏度和峯度的Z評分(Z-score)。
偏度Z-score = 偏度值 / 偏度值的標準差
峯度Z-score = 峯度值 / 峯度值的標準差
在 a=0.05的檢驗水平下,偏度Z-score和峯度Z-score是否滿足假設條件下所限制的變量範圍(Z-score在±1.96之間),若都滿足則可認爲服從正態分佈,若一個不滿足則認爲不服從正態分佈。

# 偏態係數
skew = df['體溫'].skew()
# 峯態係數
kurt = df['體溫'].kurt()

print('偏態係數={}, 峯態係數={}'.format(skew, kurt))

偏態係數=-0.004419131169113917, 峯態係數=0.7804573950337397
  • 偏態係數小於0且接近0,曲線呈微左偏,大致呈對稱分佈。
  • 峯態係數大於0且接近0,說明曲線微高聳。

什麼是“偏度值的標準差”、“峯度值的標準差”?偏態係數和峯態係數不是一個具體的值嗎?怎麼會有標準差可計算?

樣本的增加會減小偏度值和峯度值的標準差,相應的Z-score會變大,最終會拒絕條件假設,會給正確判斷樣本數據的正態性情況造成一定的干擾。因此,當樣本量小於100時,用偏度和峯度來判斷樣本的正態分佈性比較合理。
由於這裏的樣本量大於100個,因此不太適合使用此方法判斷是否滿足正態分佈。

好了,反正不適合用這種方法判斷,那我就不弄這個了。有知道的朋友請告訴我!


方法二:通過Kolmogorov-Smirnov檢驗(K-S檢驗)判斷

  • statistic:D值;
  • pvalue:P值。

當P>0.05時,可以認爲數據是呈正態分佈的,小於爲非正態性。

from scipy import stats

u = df['體溫'].mean()  # 計算均值
std = df['體溫'].std()  # 計算標準差
ks_test = stats.kstest(df['體溫'], 'norm',(u,std))
print(ks_test)
KstestResult(statistic=0.06472685044047233, pvalue=0.6450307317438662)

結果顯示p-value大於顯著性水平0.05,所以不能拒絕零假設:樣本來自正態分佈。



方法三:通過Shapiro- Wilk (W 檢驗)判斷

  • W的值越接近1就越表明數據和正態分佈擬合得越好;

  • P值>指定水平, 不拒絕原假設,可以認爲樣本數據服從正態分佈;

  • 不適合樣本>5000的情況;

  • W:統計數;

  • p-value:p值。

當P>0.05時,可以認爲數據是呈正態分佈的,小於爲非正態性。

import scipy.stats as stats
w, p = stats.shapiro(df['體溫'])
print(w, p)
0.9865770936012268 0.233174666762352

結果顯示p-value大於顯著性水平0.05,所以不能拒絕零假設:樣本來自正態分佈。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章