数据挖掘之统计学基础(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,所以不能拒绝零假设:样本来自正态分布。




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