前言:
本文是笔者备战24年国赛数模的记录,如有错误,请留言,不胜感激。
目录
1. 数据与大数据
1.1 何为数据?
事实上,各类学科中、万事万物都可以看做是数据在不同载体中的体现,各种 模态 的数据均可以进行“数化”,人类能够感知和认识的信息,计算机同样可以进行处理。
【注意】:这里的模态是指 信息的不同形式,包括:
- 数值类数据,例如结构化的excel表格和SQL文件。
- 文本类数据,例如新闻报道、微博评论、餐饮点评等文字。
- 图像类数据,以一定尺寸的黑白或彩色图像在计算机内存储。
- 音频类数据,例如音乐、电话录音等。
- 信号类数据,例如地震波的波形、电磁波信号、脑电信号等。
1.2 如何将不同模态的数据“数字化”?
虽然我们上面说数据藏匿在不同模态中,但是,我们在进行数学建模的过程中,自然还是希望将其“数字化”,以便于更好的进行模型训练。
文本变为数据,只需要做词频统计、TF-IDF、词嵌入等操作就可以“数化”;图像变为数据,因为它在计算机内本身就是以RGB三个通道的大矩阵在存储每个像素点的颜色信息;音频和信号类数据则更为简单,它本身可以视作一个波,用信号与系统的概念和方法也可以对其“数化”。
1.3 何为大数据
数据和大数据的区别,兹以为有以下三点:
- 体量上:大数据的体量之大:一般用TB甚至PB、ZB衡量
我们应该根据数据的体量去选择合适的分析方法,焉能牛刀鲨小鸡? 这样不仅造成资源浪费,且效果往往不是很好。
2. 数据的预处理
相信如果参加过数学建模比赛的人,往往拿到数据的第一步就是数据预处理,这是因为,我们拿到的数据通常不是那么规则的,而是充斥着空缺、重复和异常。
2.1 数据文件的基本认识
- 最上面一行,称为表头
- 表头的每一个格子叫做字段,每个字段描述了这一列数据表示的意义
- 表格的体量则是它有多少行多少列
- 稀疏的定义:
- 1.有些稀疏——列数超过了行数的1/2
- 2.严重稀疏——列数是行数的3倍
- 3.表格里面很多都是空白的或者全是0
- 数据的每一列称其为一个属性,有多少个属性又可以称之有多少维
- 属性:分为离散和连续。很好理解,离散就是一个属性只有几个固定的取值(注意:这里的取值,不只是局限于数字,比如出行方式:{汽车、火车、飞机})
2.2 使用pandas进行数据的处理——插值、填充、删除
(1)对于数据重复:直接删除
(2)对于数据缺失:
- 数据项(数表一行称作一个数据项 )缺失率在5%以内:如果问题允许可以把行删掉
- 5%-20% :使用填充(常数填充、均值填充 )、插值
- 20%-40% :使用预测方法进行填充
- 如果一行数据有50%以上都是缺失的,如果条件允许,我们可以把这一列都删掉
df = pd.DataFrame({'From_To': ['LoNDon_paris', 'MAdrid_miLAN', 'londON_StockhOlm',
'Budapest_PaRis', 'Brussels_londOn'],
'FlightNumber': [10045, np.nan, 10065, np.nan, 10085],
'RecentDelays': [[23, 47], [], [24, 43, 87], [13], [67, 32]],
'Airline': ['KLM(!)', '<Air France> (12)', '(British Airways. )',
'12. Air France', '"Swiss Air"']})
df
From_To | FlightNumber | RecentDelays | Airline | |
---|---|---|---|---|
0 | LoNDon_paris | 10045.0 | [23, 47] | KLM(!) |
1 | MAdrid_miLAN | NaN | [] | <Air France> (12) |
2 | londON_StockhOlm | 10065.0 | [24, 43, 87] | (British Airways. ) |
3 | Budapest_PaRis | NaN | [13] | 12. Air France |
4 | Brussels_londOn | 10085.0 | [67, 32] | "Swiss Air"数据的 |
(3)插值模型
1. 线性插值
import numpy as np
#数据准备
X = np.arange(-2*np.pi, 2*np.pi, 1) # 定义样本点X,从-pi到pi每次间隔1
Y = np.sin(X) # 定义样本点Y,形成sin函数
new_x = np.arange(-2*np.pi, 2*np.pi, 0.1) # 定义插值点
# 进行样条插值
import scipy.interpolate as spi
# 进行一阶样条插值
ipo1 = spi.splrep(X, Y, k=1) # 样本点导入,生成参数
iy1 = spi.splev(new_x, ipo1) # 根据观测点和样条参数,生成插值
2. 三次样条插值
# 进行三次样条拟合
ipo3 = spi.splrep(X, Y, k=3) # 样本点导入,生成参数
iy3 = spi.splev(new_x, ipo3) # 根据观测点和样条参数,生成插值
3.拉格朗日插值
def lagrange(x0,y0,x):
y=[]
for k in range(len(x)):
s=0
for i in range(len(y0)):
t=y0[i]
for j in range(len(y0)):
if i!=j:
t*=(x[k]-x0[j])/(x0[i]-x0[j])
s+=t
y.append(s)
return y
2.3 数据的规约
两种典型的规约方式
(1) min-max规约:
所有的属性都会被规约到【0,1】的范围内,但是对异常值表现明显,即如果出现异常值,这个数据的分布就是有偏的。
(2)Z-score规约:
本质上,一列数据减去其均值再除以标准差,如果这一列数据近似服从正态分布,这个过程就是化为标准正态分布的过程。Z-score规约和min-max规约往往不是二者取其一,有时候两个可以组合起来用。
3. 常见的统计分析模型
3.1 回归分析与分类分析
回归分析中因变量是连续变量,如工资、销售额;而分类分析中因变量是属性变量,如判断邮件“是or否”为垃圾邮件。
(1)回归分析:在学生刚入大学时,大学通常会举办一个大学入学考试,该成绩虽然没什么用,但是能让刚入学的学生保持持续学习的警示。现在,我们想分析大学成绩GPA是否与入学成绩以及高考成绩有关?
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import stats
import seaborn as sns
from IPython.display import display
import statsmodels.api as sm
# 加载数据
gpa1=pd.read_stata('./data/gpa1.dta')
# 在数据集中提取自变量(ACT为入学考试成绩、hsGPA为高考成绩)
X1=gpa1.ACT # x1 是只有 一个入学成绩
X2=gpa1[['ACT','hsGPA']] # x2是含有入学成绩和高考成绩
# 提取因变量
y=gpa1.colGPA
# 为自变量增添截距项
X1=sm.add_constant(X1)
X2=sm.add_constant(X2)
display(X2)
# 拟合两个模型
gpa_lm1=sm.OLS(y,X1).fit()
gpa_lm2=sm.OLS(y,X2).fit()
# 输出两个模型的系数与对应p值
p1=pd.DataFrame(gpa_lm1.pvalues,columns=['pvalue'])
c1=pd.DataFrame(gpa_lm1.params,columns=['params'])
p2=pd.DataFrame(gpa_lm2.pvalues,columns=['pvalue'])
c2=pd.DataFrame(gpa_lm2.params,columns=['params'])
display(c1.join(p1,how='right'))
display(c2.join(p2,how='right'))
注意:X1=gpa1.ACT # x1 是只有 一个入学成绩
X2=gpa1[['ACT','hsGPA']] # x2是含有入学成绩和高考成绩
我们分析结果 首先看第一个拟合模型结果, 1.3899927e-02 小于 0.05 ,因此入学成绩能显著影响大学成绩
但从模型II可以看到,高考成绩haGPA的pvalue为0.000005远小于0.05,说明高考成绩haGPA显著影响大学成绩GPA,但大学入学考试成绩ACT的pvalue为0.38大于0.05,不能说明大学入学考试成绩ACT显著影响大学成绩GPA。
显然,模型1 和 模型2 的结果是相悖的, 这是为什么呢?
对于模型1和2,两者的区别就是,影响因素的选择不同 ,模型1只有 一个入学成绩,而模型2 含有入学成绩和高考成绩
所以出现相悖结果的原因就是 高考成绩和大学入学考试成绩的相关性也很高,但是高考考试成绩对GPA的影响更加显著,就显得大学成绩的影响不那么显著了。
3.2 假设检验
这里需要注意的是,在实际应用中,我们应该考虑到数据的复杂性,考虑同时使用多种方法进行判断
# 接下来,我们在python中定义一个函数,将概率图、Shapiro-Wilk test、D'Agostino's K-squared test结合在一起。
data_small = stats.norm.rvs(0, 1, size=30) # 小样本正态性数据集
data_large = stats.norm.rvs(0, 1, size=6000) # 大样本正态性数据集
# 定义一个正态性检验函数,它可以输出:
## 正态概率图
## 小样本Shapiro-Wilk检验的p值
## 大样本D'Agostino's K-squared检验的p值
from statsmodels.stats.diagnostic import lilliefors
from typing import List
def check_normality(data: np.ndarray, show_flag: bool=True) -> List[float]:
"""
输入参数
----------
data : numpy数组或者pandas.Series
show_flag : 是否显示概率图
Returns
-------
两种检验的p值;概率图
"""
if show_flag:
_ = stats.probplot(data, plot=plt)
plt.show()
pVals = pd.Series(dtype='float64')
# D'Agostino's K-squared test
_, pVals['Omnibus'] = stats.normaltest(data)
# Shapiro-Wilk test
_, pVals['Shapiro-Wilk'] = stats.shapiro(data)
print(f'数据量为{len(data)}的数据集正态性假设检验的结果 : ----------------')
print(pVals)
check_normality(data_small,show_flag=True)
数据量为30的数据集正态性假设检验的结果 : ----------------
Omnibus 0.703004
Shapiro-Wilk 0.898077
数据量为6000的数据集正态性假设检验的结果 : ----------------
Omnibus 0.980014
Shapiro-Wilk 0.992427
3.3 随机过程和随机模拟
maybe可以使用随机模拟出一些数据???
4.数据可视化
R语言在数据可视化领域具有大一统的地位,Matplotlib、Seaborn等数据可视化包 的使用建立在大量代码语句上,而Plotnine作为ggplot2 在python上的移植版,会更适合数据可视化 (相当于ps,每个代码都是加上一个图