概述
对上周的抽样分布理论知识进行实践。
数据集:https://pan.baidu.com/s/1rvxlWe4LzlHx5td7zYGTTg 提取码: us2a
数据集描述:数据包括【ID、年龄、价格、港口】
问题1:按照港口分类,使用Python求出各类数据年龄和价格的统计量(方差、均值等)
问题2:画出价格的分布图像,验证数据服从何种分布(卡方?正态?T分布?)
问题3:按照港口分类,验证S港与Q港两个港口之间的平均价格之差是否服从某种分布?
计算统计量
import pandas as pd
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
data = pd.read_excel("C:\\data\\data.xlsx")
data.head()
输出为:
#按照港口分类求出统计量:均值/方差/标准差
age_df = pd.DataFrame()
fare_df = pd.DataFrame()
group = data.groupby('Embarked')
age_df['mean'] = group.mean()['Age']
age_df['var'] = group.var()['Age']
age_df['std'] = group.std()['Age']
age_df['cv'] = age_df['std']/age_df['mean']
age_df['max'] = group.max()['Age']
age_df['min'] = group.min()['Age']
age_df['median'] = group.median()['Age']
age_df['count'] = group.count()['Age']
print("----年龄统计量-----")
print(age_df)
输出为:
fare_df['mean'] = group.mean()['Fare']
fare_df['var'] = group.var()['Fare']
fare_df['std'] = group.std()['Fare']
fare_df['cv'] = fare_df['std']/fare_df['mean']
fare_df['max'] = group.max()['Fare']
fare_df['min'] = group.min()['Fare']
fare_df['median'] = group.median()['Fare']
fare_df['count'] = group.count()['Fare']
print("----价格统计量-----")
print(fare_df)
输出为:
分析
简单分析一波:
三个港口登船的年龄分布都相差不多
S港的登船人数最多,Q港的最少。
S港的船票价格出现了0,综合S港登船人数多,S港可能出现了逃票。
最贵的船票出现在C港,但是C港的船票价格均值与中位数并不高,可能出现了某几个豪华仓的土豪。
验证数据服从何种分布
通常使用 Shapiro-Wilk 检验来判断样本是否服从正态分布,如下:
fare = data['Fare'].copy().values
W,p = stats.shapiro(fare)
print("W=%.4f, p=%.4f" % (W, p))
# W=0.5257, p=0.0000
# p < 0.05 ,所以拒绝样本服从正态分布的假设
绘制样本分布图像:
#解决乱码
plt.rcParams['font.sans-serif']=['Simhei'] #解决中文显示问题
plt.rcParams['axes.unicode_minus']=False #解决负数坐标显示问题
loc, scale = stats.norm.fit(fare)
y = stats.norm.pdf(fare, loc, scale)
plt.hist(fare, bins=10, density=True, label='价格分布')
plt.xlabel("价格")
plt.ylabel("密度")
plt.title('价格分布')
plt.legend()
plt.show()
输出图像为:
看图像感觉有点像卡方分布,我们来校验一下。
卡方分布没有类似正态分布校验的直接方法,我们可以使用 ks_2samp校验 来校验两个样本是否服从同一分布。
可以先用正态分布测试一下这个方法:
# 生成服从正态分布的随机变量
x1 = stats.norm.rvs(loc=loc, scale=scale, size=len(fare))
ks, p = stats.ks_2samp(fare, x1)
print("ks=%.4f, p=%.4f" % (ks, p))
# out--->
# ks=0.6138, p=0.0000
# p < 0.05 拒绝两者服从同一分布的假设,所以价格不服从正态分布
# ks_2samp和shapiro校验结果一致,说明没毛病。
使用ks_2samp校验价格分布是否服从卡方分布和T分布:
x1 = stats.chi2.rvs(df=df, loc=loc, scale=scale, size=len(fare))
ks, p = stats.ks_2samp(fare, x1)
print("ks=%.4f, p=%.4f" % (ks, p))
# ks=0.2093, p=0.0000
# p小于0.05,拒绝假设,认为价格肯定不服从卡方分布
x1 = stats.t.rvs(df=df, loc=loc, scale=scale, size=len(fare))
ks, p = stats.ks_2samp(fare, x1)
print("ks=%.4f, p=%.4f" % (ks, p))
# ks=0.6110, p=0.0000
# p小于0.05,拒绝假设,认为价格不服从t分布
结论
价格数据不满足正态、卡方、以及T分布。
验证港口之间的平均价格之差是否服从某种分布
知识点
根据中心极限定理:无论总体满足何种分布,只要从总体中抽取的样本容量足够大,这些样本组成的样本均值的抽样分布都近似正态分布
。通常认为样本容量大于30的样本均值分布服从正态分布。
如果两个总体均服从正态分布,则其差也服从正态分布。均值和方差分别为:
E
(
X
1
−
X
2
)
=
E
(
X
1
)
−
E
(
X
2
)
=
μ
1
−
μ
2
E(X_1 - X_2) = E(X_1) - E(X_2) = \mu_1 - \mu_2
E(X1−X2)=E(X1)−E(X2)=μ1−μ2
D ( X 1 − X 2 ) = D ( X 1 ) − D ( X 2 ) = σ 1 2 n 1 + σ 2 2 n 2 D(X_1 - X_2) = D(X_1) - D(X_2) = \frac{\sigma_1^2}{n_1} + \frac{\sigma_2^2}{n_2} D(X1−X2)=D(X1)−D(X2)=n1σ12+n2σ22
解题
查看各港口的数量:
print(fare_df['count'])
'''
Embarked
C 130
Q 28
S 554
'''
可以看出,Q港口的数量比较少,低于30。
所以Q港的均值分布,必然不服从正态分布。所以S港与Q港两个港口之间的平均价格之差必然不服从正态分布
我们可以接着验证C港和S港的平均价格之差是否服从正态分布?
根据C港和S港的 均值和标准差绘制 平均价格之差的分布图像:
s_fare = data[data['Embarked'] == 'S']['Fare'].copy().values
c_fare = data[data['Embarked'] == 'C']['Fare'].copy().values
# 计算均值与标准差
mu = np.mean(s_fare) - np.mean(c_fare)
sigma = np.sqrt(np.var(s_fare, ddof=1)/len(s_fare) + np.var(c_fare, ddof=1)/len(c_fare))
# 根据均值和标准差绘制密度曲线
x = np.arange(- 100, 20)
y = stats.norm.pdf(x, mu, sigma)
plt.plot(x, y)
plt.xlabel("S港与C港的平均价格之差曲线")
plt.ylabel("密度")
plt.title('S港与C港的平均价格差\n$\mu=%.2f,\quad \sigma=%.2f$' % (mu, sigma))
plt.show()
输出图像为:
结论
可以看出,S港为C港的平均价格之差服从正态分布。