第4章 概率论与数理统计
概率论与数理统计是数学中的一个有特色的分支,具有自己独特的概念和方法,内容丰富,与很多学科交叉相连,广泛应用于工业、农业、军事和科学技术领域。随机变量的概率计算和数字特征
描述性统计和统计图
参数估计和假设检验
方差分析
一元线性回归模型
常用的数据清洗方法
1.随机变量的概率计算和数字特征
1)随机变量的概率计算
例:设
,
(1)求
;
(2)确定c,使得
代码如下:
from scipy.stats import norm
from scipy.optimize import fsolve
print("p=", norm.cdf(6, 3, 5) - norm.cdf(2, 3, 5))
f = lambda c: norm.cdf(2 * c, 3, 5) - norm.cdf(-3 * c, 3, 5) - 0.6
print("c=", fsolve(f, 0))
运行结果:
例:设
,若
满足条件
,则称
为标准正态分布的上
分位数.试计算几个常用的
的值,并画出
的示意图.
from scipy.stats import norm
from pylab import plot, fill_between, show, text, savefig, rc
from numpy import array, linspace, zeros
alpha = array([0.001, 0.005, 0.01, 0.025, 0.05, 0.10])
za = norm.ppf(1 - alpha, 0, 1) # 求上alpha分位数
print("上alpha分位数分别为", za)
x = linspace(-4, 4, 100)
y = norm.pdf(x, 0, 1)
rc('font', size=16)
rc('text', usetex=False)
plot(x, y) # 画标准正态分布密度曲线
x2 = linspace(za[-1], 4, 100)
y2 = norm.pdf(x2)
y1 = [0] * len(x2)
fill_between(x2, y1, y2, color='r') # y1,y2对应的点之间填充
plot([-4, 4], [0, 0]) # 画水平线
text(1.9, 0.07, "$\\leftarrow\\alpha$=0.1") # 标注
savefig("figure4_2.png", dpi=500)
show()
运行结果:
2)随机变量数字特征简介
3)随机变量数字特征计算及应用
例:计算二项分布b(20,0.8)的均值和方差.
from scipy.stats import binom
n, p = 20, 0.8
print("期望和方差分布为:", binom.stats(n, p))
运行结果:
例:计算二项分布b(20,0.8)的均值、方差、偏度和峰度.
from scipy.stats import binom
n, p = 20, 0.8
mean, variance, skewness, kurtosis = binom.stats(n, p, moments='mvsk')
# 上述语句不显示,只为了说明数据顺序
print("所求的数字特征为:", binom.stats(n, p, moments='mvsk'))
运行结果:
例:路灯维修周期问题.(详细见P126)
from scipy.integrate import quad
from numpy import exp, sqrt, pi, abs
a = 80
b = 0.02
BD = a/b
mu = 4000
s = 100
y = lambda x: x * exp(-(x-mu)**2/(2*s**2))/sqrt(2*pi)/s # 定义积分的被积函数
I = 0
x1 = 0
x2 = 10000
while abs(I - BD) > 1E-16:
c = (x1 + x2) / 2
I = quad(y, -10000, c)[0] # 由3sigma准则这里积分下限取为-10000,取零效果一样
if I > BD:
x2 = c
else:
x1 = c
print("最佳更换周期为:", c)
运行结果:
2.描述性统计和统计图
数理统计研究的对象是受随机因素影响的数据,简称统计。统计是以概率论为基础的一门应用学科。数据样本少则几个,多则成千万个,人们希望能用少数几个包含最多相关信息的数据来体现所研究对象的规律。描述性统计就是搜集、整理、加工和分析统计数据,使之系统化、条理化,以显示出数据资料的趋势、特征和数量关系。它是统计推断的基础,实用性较强,在统计工作中经常使用。
1)统计的基础知识
2)用Python计算统计量
使用NumPy库中的函数可以计算统计量,也可以使用sciy.stats中的函数计算统计量。
NumPy库中计算统计量的函数如下表所示:函数meanmedianptpvarstdcovcorrcoef
功能均值中位数极差方差标准差协方差相关系数
例:学校随机抽取100名学生,测量他们的身高和体重,所得数据如下表,试分别求身高的均值、中位数、极差、方差、标准差;计算身高与体重的协方差、相关系数。
代码如下:
from numpy import reshape, hstack, mean, median, ptp, var, std, cov, corrcoef
import pandas as pd
df = pd.read_excel("Pdata4_6_1.xlsx", header=None)
a = df.values # 提取数据矩阵
h = a[:, ::2] # 提取奇数列身高
w = a[:, 1::2] # 提取偶数列体重
h = reshape(h, (-1, 1)) # 转换成列向量,自动计算行数
w = reshape(w, (-1, 1)) # 转换成列向量,自动计算行数
hw = hstack([h, w]) # 构造两列的数组
print([mean(h), median(h), ptp(h), var(h), std(h)]) # 计算均值,中位数,极差,方差,标准差
print("协方差为:{}\n相关系数为:{}".format(cov(hw.T)[0, 1], corrcoef(hw.T)[0, 1]))
运行结果:
使用Pandas的DataFrame计算统计量:
上例,使用Pandas的describe方法计算相关统计量,并计算身高和体重的偏度、峰度和样本的25%,50%,90%分位数。
代码如下:
from numpy import reshape, c_
import pandas as pd
df = pd.read_excel("Pdata4_6_1.xlsx", header=None)
a = df.values
h1 = a[:, ::2]
w1 = a[:, 1::2]
h2 = reshape(h1, (-1, 1))
w2 = reshape(w1, (-1, 1))
df2 = pd.DataFrame(c_[h2, w2], columns=["身高", "体重"]) # 构造数据框
print("求得的描述统计量如下:\n", df2.describe())
print("偏度为:\n", df2.skew())
print("峰度为:\n", df2.kurt())
print("分位数为:\n", df2.quantile(0.9))
运行结果:
3)统计图
例:画图身高和体重的直方图,并统计从最小体重到最大体重,等间距分成6个小区间时,数据出现在每个小区间的频次。
代码如下:
import numpy as np
import matplotlib.pyplot as plt
a = np.loadtxt("Pdata4_6_2.txt")
h = a[:, ::2]
w = a[:, 1::2]
h = np.reshape(h, (-1, 1))
w = np.reshape(w, (-1, 1))
plt.rc('font', size=16)
plt.rc('font', family="SimHei")
plt.subplot(121)
plt.xlabel("身高")
plt.hist(h, 10) # 只画直方图不返回频数表
plt.subplot(122)
ps = plt.hist(w, 6) # 画图并返回频数表ps
plt.xlabel("体重")
print("体重的频数表为:", ps)
plt.savefig("figure4_8.png", dpi=500)
plt.show()
运行结果:
例:下面分别给出了25个男子和25个女子的肺活量数据(以L计,数据已经排过序),试画出箱线图。
代码如下:
import numpy as np
import matplotlib.pyplot as plt
a = np.loadtxt("Pdata4_9.txt") # 读入两行的数据
b = a.T # 转置成两列的数据
plt.rc('font', size=16)
plt.rc('font', family='SimHei')
plt.boxplot(b, labels=['女子', '男子'])
plt.savefig('figure4_9.png', dpi=500)
plt.show()
运行结果:
例:画出身高和体重的箱线图(找疑似异常值)
代码如下:
import numpy as np
import matplotlib.pyplot as plt
a = np.loadtxt("Pdata4_6_2.txt")
h = a[:, ::2]
w = a[:, 1::2]
h = np.reshape(h, (-1, 1))
w = np.reshape(w, (-1, 1))
hw = np.hstack((h, w))
plt.rc('font', size=16)
plt.rc('font', family='SimHei')
plt.boxplot(hw, labels=['身高', '体重'])
plt.savefig("figure4_10.png", dpi=500)
plt.show()
运行结果:
经验分布函数图形:参考样本分布函数_百度百科
例:画出体重的经验分布函数图形.
代码如下:
import numpy as np
import matplotlib.pyplot as plt
a = np.loadtxt("Pdata4_6_2.txt")
w = a[:, 1::2]
w = np.reshape(w, (-1, 1))
plt.rc('font', size=16)
h = plt.hist(w, 20, density=True, histtype='step', cumulative=True)
print(h)
plt.grid()
plt.savefig("figure4_11.png", dpi=500)
plt.show()
运行结果:
例:对于上例的身高数据,如果它们来自正态分布,求该正态分布的参数,试画出它们的Q-Q图,判断拟合结果.
代码如下:
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm, probplot
a = np.loadtxt("Pdata4_6_2.txt")
h = a[:, ::2]
h = h.flatten()
mu = np.mean(h)
s = np.std(h)
print([mu, s])
sh = np.sort(h) # 按从小到大排序
n = len(sh)
xi = (np.arange(1, n + 1) - 1 / 2) / n
yi = norm.ppf(xi, mu, s)
plt.rc('font', size=16)
plt.rc('font', family='SimHei')
plt.rc('axes', unicode_minus=False) # 用来正常显示负号
plt.subplot(121)
plt.plot(yi, sh, 'o', label='QQ图')
plt.plot([155, 185], [155, 185], 'r-', label='参照直线')
plt.legend()
plt.subplot(122)
res = probplot(h, plot=plt)
plt.savefig("figure4_12.png", dpi=500)
plt.show()
运行结果:
3.参数估计和假设检验
1)参数估计
参数估计是利用样本对总体进行统计推断的一类方法,即假定总体的概率分布类型已知,但其中含有未知参数,由样本估计未知参数的值。参数估计的方法主要有点估计和区间估计,其中点估计中有矩估计和极大似然估计等方法。
极大似然估计
假定前例中学生的身高服从正态分布,求总体均值和标准差的极大似然估计.
代码如下:
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
a = np.loadtxt("Pdata4_6_2.txt")
h = a[:, ::2]
h = h.flatten()
mu = np.mean(h)
s = np.std(h)
print("样本均值和标准差为:", [mu, s])
print("极大似然估计值为:", norm.fit(h))
运行结果:
区间估计
例:糖果重量区间估计,题目详细内容见书P141.
代码如下(三种方法):
from numpy import array, sqrt
from scipy.stats import t
a = array([506, 508, 499, 503, 504, 510, 497, 512,
514, 505, 493, 496, 506, 502, 509, 496])
# ddof取值为1时,标准偏差除的是(N-1);NumPy中的std计算默认是除以N
mu = a.mean()
s = a.std(ddof=1) # 计算均值和标准差
print(mu, s)
alpha = 0.05
n = len(a)
val = (mu - s/sqrt(n)*t.ppf(1 - alpha/2, n - 1), mu+s/sqrt(n)*t.ppf(1 - alpha/2, n - 1))
print("置信区间为:", val)
import numpy as np
import scipy.stats as ss
from scipy import stats
a = np.array([506, 508, 499, 503, 504, 510, 497, 512,
514, 505, 493, 496, 506, 502, 509, 496])
alpha = 0.95
df = len(a) - 1
ci = ss.t.interval(alpha, df, loc=a.mean(), scale=ss.sem(a))
print("置信区间为:", ci)
import numpy as np
from statsmodels.stats.weightstats import zconfint
a = np.array([506, 508, 499, 503, 504, 510, 497, 512,
514, 505, 493, 496, 506, 502, 509, 496])
ci = zconfint(a)
print("置信区间为:", ci)
运行结果:
参数假设检验
Z检验(正态总体标准差
已知):
import numpy as np
from statsmodels.stats.weightstats import ztest
sigma = 0.015
a = np.array([0.497, 0.506, 0.518, 0.524, 0.498, 0.511, 0.520, 0.515, 0.512])
tstat1, pvalue = ztest(a, value=0.5) # 计算T统计量的观测值及p值
tstat2 = tstat1 * a.std(ddof=1) / sigma # 转换为Z统计量的观测值
print('t值为:', round(tstat1, 4))
print('z值为:', round(tstat2, 4))
print('p值为:', round(pvalue, 4))
运行结果:
t检验(正态总体标准差
未知):
import numpy as np
from statsmodels.stats.weightstats import ztest
a = np.array([3.25, 3.27, 3.24, 3.26, 3.24])
tstat, pvalue = ztest(a, value=3.25)
print('检验统计量为:', tstat)
print('p值为:', pvalue)
运行结果:
例:罐头合格率检测(详细见P145).
import numpy as np
from statsmodels.stats.weightstats import ztest
a = np.array([16, 25, 21, 20, 23, 21, 19, 15, 13,
23, 17, 20, 29, 18, 22, 16, 22])
tstat, pvalue = ztest(a, value=21, alternative='smaller')
print('检验统计量为:', tstat)
print('p值为:', pvalue)
运行结果:
两个总体均值的假设检验:
例:Mark Twain和Snodgrass作品中3字母单词比例检验.(详见P145)
import numpy as np
from statsmodels.stats.weightstats import ttest_ind
a = np.array([0.225, 0.262, 0.217, 0.240, 0.230, 0.229, 0.235, 0.217])
b = np.array([0.209, 0.205, 0.196, 0.210, 0.202, 0.207,
0.224, 0.223, 0.220, 0.201])
tstat, pvalue, df = ttest_ind(a, b, value=0)
print('检验统计量为:', tstat)
print('p值为:', pvalue)
print('自由度为:', df)
运行结果:
非参数假设检验
在实际建模中,对样本数据服从什么分布,完全是未知的,需要进行非参数假设检验。本书介绍了两种非参数假设检验方法:分布拟合检验和Kolmogorov-Smironv检验.
分布拟合检验:
例:交通事故与星期几相关.详见P147.
import numpy as np
import scipy.stats as ss
bins = np.arange(1, 8)
mi = np.array([36, 23, 29, 31, 34, 60, 25])
n = mi.sum()
p = np.ones(7)/7
cha = (mi - n*p)**2/(n*p)
st = cha.sum()
bd = ss.chi2.ppf(0.95, len(bins) - 1) # 计算上alpha分位数
print("统计量为:{},临界值为:{}".format(st, bd))
运行结果:
例:滚珠直径分布检验,详见P148.
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as ss
n = 50
k = 8 # 初始小区间划分的个数
a = np.loadtxt("Pdata4_20.txt")
a = a.flatten()
mu = a.mean()
s = a.std()
print("均值为:", mu)
print("标准差为:", s)
print("最大值为:", a.max())
print("最小值为:", a.min())
bins = np.array([14.2, 14.625, 14.8375, 15.05, 15.2625, 15.475, 15.9])
h = plt.hist(a, bins)
f = h[0]
x = h[1] # 提取各个小区间的频数和小区间端点的取值
print("各区间的频数为:", f, "\n小区间端点值为:", x)
p = ss.norm.cdf(x, mu, s) # 计算各个分点分布函数的取值
dp = np.diff(p) # 计算各小区间取值的理论概率
dp[0] = ss.norm.cdf(x[1], mu, s) # 修改第一个区间的概率值
dp[-1] = 1 - ss.norm.cdf(x[-2], mu, s) # 修改最后一个区间的概率值
print("各小区取值的理论概率为:", dp)
st = sum(f ** 2 / (n * dp)) - n # 计算卡方统计量的值
bd = ss.chi2.ppf(0.95, k - 5) # 计算上alpha分位数
print("统计量为:{},临界值为:{}".format(st, bd))
运行结果:
Kolmogorov-Smironv检验:
例:检验学生体重是否服从正态分布.
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as ss
a = np.loadtxt("Pdata4_6_2.txt")
w = a[:, 1::2]
w = w.flatten()
mu = w.mean()
s = w.std(ddof=1) # 计算样本均值和标准差
print("均值和标准差分别为:", (mu, s))
statVal, pVal = ss.kstest(w, 'norm', (mu, s))
print("统计量和P值分别为:", [statVal, pVal])
运行结果:
4.方差分析
方差分析是用于两个及两个以上总体均值差别的显著性检验.(本小节后续使用到的时候还要认真学习)
1)单因素方差分析及Python实现
例:灯泡制造因素分析,详见P153
import numpy as np
import statsmodels.api as sm
y = np.array([1620, 1670, 1700, 1750, 1800, 1580, 1600, 1640, 1720,
1460, 1540, 1620, 1680, 1500, 1550, 1610])
x = np.hstack([np.ones(5), np.full(4, 2), np.full(4, 3), np.full(3, 4)])
d = {'x': x, 'y': y} # 构造字典
model = sm.formula.ols("y~C(x)", d).fit() # 构建模型
anovat = sm.stats.anova_lm(model) # 进行单因素方差分析
print(anovat)
运行结果:
例:劳动生产率分析,详见P155
import numpy as np
import pandas as pd
import statsmodels.api as sm
df = pd.read_excel("Pdata4_23.xlsx", header=None)
a = df.values.T.flatten()
b = np.arange(1, 6)
x = np.tile(b, (4, 1)).T.flatten()
d = {'x': x, 'y': a} # 构造求解需要的字典
model = sm.formula.ols("y~C(x)", d).fit() # 构建模型
anovat = sm.stats.anova_lm(model) # 进行单因素方差分析
print(anovat)
运行结果:
2)双因素方差分析及Python实现
例:浓度、温度化工制备问题,详见P159
import numpy as np
import statsmodels.api as sm
y = np.array([[11, 11, 13, 10], [10, 11, 9, 12],
[9, 10, 7, 6], [7, 8, 11, 10],
[5, 13, 12, 14], [11, 14, 13, 10]]).flatten()
A = np.tile(np.arange(1, 5), (6, 1)).flatten()
B = np.tile(np.arange(1, 4).reshape(3, 1), (1, 8)).flatten()
d = {'x1': A, 'x2': B, 'y': y}
model = sm.formula.ols("y~C(x1)+C(x2)+C(x1):C(x2)", d).fit() # 注意交互作用公式的写法
anovat = sm.stats.anova_lm(model) # 进行双因素方差分析
print(anovat)
运行结果:
5.一元线性回归模型
变量间的关系有两类:一类可用函数关系表示,成为确定性关系;另一类关系不能用函数来表示,称为相关关系。具有相关关系的变量虽然不具有确定性的函数关系,但可以借助函数关系来表示它们之间的统计规律。回归分析方法是处理变量之间相关关系的一种统计方法,它不仅提供建立变量间关系的数学表达式——经验公式,而且利用概率统计知识进行了分析讨论,从而判断经验公式的正确性。
1)一元线性回归分析
例:适量饮用葡萄酒可以预防心脏病分析,详见P165(三种方法实现)
import matplotlib.pyplot as plt
import numpy as np
x = [2.5, 3.9, 2.9, 2.4, 2.9, 0.8, 9.1, 0.8, 0.7, 7.9, 1.8, 1.9, 0.8, 6.5, 1.6, 5.8, 1.3, 1.2, 2.7]
y = [211, 167, 131, 191, 220, 297, 71, 211, 300, 107,
167, 266, 277, 86, 207, 115, 285, 199, 172]
plt.plot(x, y, '+k', label="原始数据点")
p = np.polyfit(x, y, deg=1) # 拟合一次多项式
print("拟合的多项式为:{}*x+{}".format(p[0], p[1]))
plt.rc('font', size=16)
plt.rc('font', family='SimHei')
plt.plot(x, np.polyval(p, x), label="拟合的直线")
print("预测值为:", np.polyval(p, 8))
plt.legend()
plt.savefig("figure4_25.png", dpi=500)
plt.show()
import statsmodels.api as sm
x = [2.5, 3.9, 2.9, 2.4, 2.9, 0.8, 9.1, 0.8, 0.7, 7.9,
1.8, 1.9, 0.8, 6.5, 1.6, 5.8, 1.3, 1.2, 2.7]
y = [211, 167, 131, 191, 220, 297, 71, 211, 300, 107,
167, 266, 277, 86, 207, 115, 285, 199, 172]
df = {'x': x, 'y': y}
res = sm.formula.ols('y~x', data=df).fit()
print(res.summary(), '\n')
ypred = res.predict(dict(x=8))
print('所求的预测值为:', list(ypred))
import statsmodels.api as sm
import numpy as np
x = np.array([2.5, 3.9, 2.9, 2.4, 2.9, 0.8, 9.1, 0.8, 0.7,
7.9, 1.8, 1.9, 0.8, 6.5, 1.6, 5.8, 1.3, 1.2, 2.7])
y = np.array([211, 167, 131, 191, 220, 297, 71, 211, 300,
107, 167, 266, 277, 86, 207, 115, 285, 199, 172])
X = sm.add_constant(x)
md = sm.OLS(y, X).fit() # 构建并拟合模型
print(md.params, '\n--------\n') # 提取回归系数
print(md.summary2())
ypred = md.predict([1, 8]) # 第一列必须加1
print("预测值为:", ypred)
运行结果:
6.常用的数据清洗方法
1)重复观测处理
import pandas as pd
a = pd.read_excel("Pdata4_26_1.xlsx")
print("是否存在重复观测:", any(a.duplicated())) # 输出:True
a.drop_duplicates(inplace=True) # inplace=True时,直接删除a中的重复数据
f = pd.ExcelWriter('Pdata4_26_2.xlsx') # 创建文件对象
a.to_excel(f) # 把a写入新Excel文件中
f.save() # 保存文件,数据才真正写入Excel文件
运行结果:
2)缺失值处理
缺失值检测:
from numpy import NaN
from pandas import Series
data = Series([10.0, None, 20, NaN, 30])
print(data.isnull()) # 输出每个元素的检测结果
print("是否存在缺失值:", any(data.isnull())) # 输出:True
运行结果:
数据过滤(dropna):
from pandas import read_excel
a = read_excel("Pdata2_33.xlsx", usecols=range(1, 4))
b1 = a.dropna() # 删除所有的缺失值
b2 = a.dropna(axis=1, thresh=9) # 删除有效数据个数小于9的列
b3 = a.drop('用户B', axis=1) # 删除用户B的数据
print(b1, '\n---------------\n', b2, '\n---------------\n', b3)
运行结果(只显示b1):
数据填充(fillna)
from pandas import read_excel
a = read_excel("Pdata4_29.xlsx")
b1 = a.fillna(0) # 用0填补所有的缺失值
b2 = a.fillna(method='ffill') # 用前一行的值填补缺失值
b3 = a.fillna(method='bfill') # 用后一行的值填补,最后一行缺失值不处理
b4 = a.fillna(value={'gender': a.gender.mode()[0], # 性别使用众数替换
'age': a.age.mean(), # 年龄使用均值替换
'income': a.income.median()}) # 收入使用中位数替换
print('{}\n{}\n{}\n{}'.format(b1, b2, b3, b4))
运行结果:
uid regit_date gender age income
0 81200457 2016-10-30 M 23.0 6500.0
1 81201135 2016-11-08 M 27.0 10300.0
2 80043782 2016-10-13 F 0.0 13500.0
3 84639281 2017-04-17 M 26.0 6000.0
4 73499801 2016-03-21 0 0.0 4500.0
5 72399510 2016-01-18 M 19.0 0.0
6 63881943 2015-10-07 M 21.0 10000.0
7 35442690 2015-04-10 F 0.0 5800.0
8 77638351 2016-07-12 M 25.0 18000.0
9 85200189 2017-05-18 M 22.0 0.0
uid regit_date gender age income
0 81200457 2016-10-30 M 23.0 6500.0
1 81201135 2016-11-08 M 27.0 10300.0
2 80043782 2016-10-13 F 27.0 13500.0
3 84639281 2017-04-17 M 26.0 6000.0
4 73499801 2016-03-21 M 26.0 4500.0
5 72399510 2016-01-18 M 19.0 4500.0
6 63881943 2015-10-07 M 21.0 10000.0
7 35442690 2015-04-10 F 21.0 5800.0
8 77638351 2016-07-12 M 25.0 18000.0
9 85200189 2017-05-18 M 22.0 18000.0
uid regit_date gender age income
0 81200457 2016-10-30 M 23.0 6500.0
1 81201135 2016-11-08 M 27.0 10300.0
2 80043782 2016-10-13 F 26.0 13500.0
3 84639281 2017-04-17 M 26.0 6000.0
4 73499801 2016-03-21 M 19.0 4500.0
5 72399510 2016-01-18 M 19.0 10000.0
6 63881943 2015-10-07 M 21.0 10000.0
7 35442690 2015-04-10 F 25.0 5800.0
8 77638351 2016-07-12 M 25.0 18000.0
9 85200189 2017-05-18 M 22.0 NaN
uid regit_date gender age income
0 81200457 2016-10-30 M 23.000000 6500.0
1 81201135 2016-11-08 M 27.000000 10300.0
2 80043782 2016-10-13 F 23.285714 13500.0
3 84639281 2017-04-17 M 26.000000 6000.0
4 73499801 2016-03-21 M 23.285714 4500.0
5 72399510 2016-01-18 M 19.000000 8250.0
6 63881943 2015-10-07 M 21.000000 10000.0
7 35442690 2015-04-10 F 23.285714 5800.0
8 77638351 2016-07-12 M 25.000000 18000.0
9 85200189 2017-05-18 M 22.000000 8250.0
3)异常值处理
例:太阳黑子事件异常值处理,详见P170.
from pandas import read_csv
import matplotlib.pyplot as plt
a = read_csv("sunspots.csv")
mu = a.counts.mean() # 计算黑子个数年平均值
s = a.counts.std() # 计算黑子个数标准差
print("标准差法异常值上限检测:", any(a.counts > mu + 2 * s)) # 输出:True
print("标准差法异常值下限检测:", any(a.counts < mu - 2 * s)) # 输出:False
Q1 = a.counts.quantile(0.25) # 计算下四分位数
Q3 = a.counts.quantile(0.75) # 计算上四分位数
IQR = Q3 - Q1
print("箱线图法异常值上限检测:", any(a.counts > Q3 + 1.5 * IQR)) # 输出:True
print("箱线图法异常值下限检测:", any(a.counts < Q1 - 1.5 * IQR)) # 输出:False
plt.style.use('ggplot') # 设置绘图风格
a.counts.plot(kind='hist', bins=30, density=True) # 绘制直方图
a.counts.plot(kind='kde') # 绘制核密度曲线
plt.show()
print("异常值替换前的数据统计特征", a.counts.describe())
UB = Q3 + 1.5 * IQR
st = a.counts[a.counts < UB].max() # 找出低于判别上限的最大值
print("判别异常值的上限临界值为:", UB)
print("用以替换异常值的数据为:", st)
a.loc[a.counts > UB, 'counts'] = st # 替换超过判别上限异常值
print("异常值替换后的数据统计特征", a.counts.describe())
运行结果:
标准差法异常值上限检测: True
标准差法异常值下限检测: False
箱线图法异常值上限检测: True
箱线图法异常值下限检测: False
异常值替换前的数据统计特征 count 289.000000
mean 48.613495
std 39.474103
min 0.000000
25% 15.600000
50% 39.000000
75% 68.900000
max 190.200000
Name: counts, dtype: float64
判别异常值的上限临界值为: 148.85000000000002
用以替换异常值的数据为: 141.7
异常值替换后的数据统计特征 count 289.000000
mean 48.066090
std 37.918895
min 0.000000
25% 15.600000
50% 39.000000
75% 68.900000
max 141.700000
Name: counts, dtype: float64