详解支持向量机-SVC真实数据案例:预测明天是否会下雨-探索标签和处理异常值【菜菜的sklearn课堂笔记】

时间:2022-12-02 11:22:11

视频作者:[菜菜TsaiTsai] 链接:[【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili]

在实际工作中,数据预处理往往比建模难得多,耗时多得多,因此合理的数据预处理是非常必要的。考虑到大家渴望学习真实数据上的预处理的需求,以及SVM需要在比较规则的数据集上来表现的特性,我为大家准备了这个Kaggle上下载的,未经过预处理的澳大利亚天气数据集。我们的目标是在这个数据集上来预测明天是否会下雨。 在这里,我为大家抛砖引玉,在这个15W行数据的数据集上,随机抽样5000个样本来为大家演示我的数据预处理和特征工程的过程,为大家提供一些数据预处理和特征工程的思路。不过,特征工程没有标准答案,因此大家应当多尝试

对于使用Kaggle原数据集的小伙伴的温馨提示: 记得好好阅读Kaggle上的各种数据集说明哦~!有一些特征是不能够使用的!

特征/标签 含义
Date 观察日期
Location 获取该信息气象站的名称
MinTemp 以摄氏度为单位的最低温度
MaxTemp 以摄氏度为单位的最高温度
Rainfall 当天记录的降雨量,单位为mm
Evaporation 到早上9点之前的24小时的A级蒸发量(mm)
Sunshine 白日收到日照的完整小时
WindGustDir 在到午夜12点前的24小时中最强风的风向
WindGustSpeed 在到午夜12点前的24小时中最强风速(km/h)
WindDir9am 上午9点时的风向
WindDir3pm 下午3点时的风向
WindSpeed9am 上午9点之前每个十分钟的风速的平均值(km/h)
WindSpeed3pm 下午3点之前每个十分钟的风速的平均值(km/h)
Humidity9am 上午9点的湿度(百分比)
Humidity3am 下午3点的湿度(百分比)
Pressure9am 上午9点平均海平面上的大气压(hpa)
Pressure3pm 下午3点平均海平面上的大气压(hpa)
Cloud9am 上午9点的天空被云层遮蔽的程度,这是以“oktas”来衡量的,这个单位记录了云层遮挡天空的程度。0表示完全晴朗的天空,而8表示它完全是阴天。
Cloud3pm 下午3点的天空被云层遮蔽的程度
Temp9am 上午9点的摄氏度温度
Temp3pm 下午3点的摄氏度温度
RainTomorrow 目标变量,我们的标签:明天下雨了吗?

探索数据

from sklearn.model_selection import train_test_split
import pandas as pd
import numpy as np

weather = pd.read_csv(r'D:\ObsidianWorkSpace\SklearnData\weatherAUS5000.csv',index_col=0)
weather.head() # 22列,这里不展示了,需要什么后面会展示

# 将特征矩阵和标签分开
X = weather.iloc[:,:-1]
y = weather.iloc[:,-1]

X.shape # 原本有15万行,这里是随机取的
---
(5000, 21)

# 探索数据类型
X.info()
---
<class 'pandas.core.frame.DataFrame'>
Int64Index: 5000 entries, 0 to 4999
Data columns (total 21 columns):
Date             5000 non-null object
Location         5000 non-null object
MinTemp          4979 non-null float64
……
dtypes: float64(16), object(5)
memory usage: 859.4+ KB

# 探索缺失值
X.isnull().mean() # 缺失值所占比例
# 要有不同的缺失值填补策略
# 在本个例子中,为了展示对缺失值的处理,因此没有删除任何有缺失的数据
# 实际上,如果某个特征的缺失数据较少,可以选择直接删除含有缺失值的样本
---
Date             0.0000
Location         0.0000
MinTemp          0.0042
……
dtype: float64

np.unique(y) # 标签是二分类
---
array(['No', 'Yes'], dtype=object)

y.isnull().sum() # 标签无空值
---
0

粗略观察可以发现,这个特征矩阵由一部分分类变量和一部分连续变量组成,其中云层遮蔽程度虽然是以数字表示,但是本质却是分类变量。大多数特征都是采集的自然数据,比如蒸发量,日照时间,湿度等等,而少部分特征是人为构成的。还有一些是单纯表示样本信息的变量,比如采集信息的地点,以及采集的时间。

分训练集和测试集,恢复索引,并处理标签

Xtrain, Xtest, Ytrain, Ytest = train_test_split(X,y,test_size=0.3,random_state=420) # 随机抽样

Xtrain.head() # 结果是DataFrame
# 不展示了,但注意索引是乱的
---
5 rows × 21 columns

# 恢复索引
for i in [Xtrain,Xtest,Ytrain,Ytest]:
    i.index = range(i.shape[0])

在现实中,我们会先分训练集和测试集,再开始进行数据预处理。这是由于,测试集在现实中往往是不可获得的,或者被假设为是不可获得的,我们不希望我们建模的任何过程受到测试集数据的影响,否则的话,就相当于提前告诉了模型一部分预测的答案。先分训练集和测试集,再一步步进行预处理。这样导致的结果是,我们对训练集执行的所有操作,都必须对测试集执行一次,工作量是翻倍的。

# 先看标签,因为标签维度少,好处理
# 看是否有样本不均衡的问题
Ytrain.value_counts()
---
No     2704
Yes     796
Name: RainTomorrow, dtype: int64

# 有轻微的样本不均衡的问题
Ytrain.value_counts()[0]/Ytrain.value_counts()[1]
---
3.3969849246231156

# 将标签编码
from sklearn.preprocessing import LabelEncoder # 标签专用,允许一维数据输入
encorder = LabelEncoder().fit(Ytrain)
# 这一步就是让模型知道标签有两类,Yes和No

# 使用训练集训练,然后在训练集和测试集上分别进行transform
Ytrain = pd.DataFrame(encorder.transform(Ytrain))
Ytest = pd.DataFrame(encorder.transform(Ytest))

# 如果我们的测试集中,出现了训练集中没有过的标签类别,比如有Unknown
# 而我们的训练集中只有Yes和No
# 如果遇到这种情况,需要重新划分训练集测试集或者重新建模

Ytrain.head()
---
	0
0	0
1	0
2	0
3	1
4	0

建议标签处理好后,用数据集.to_csv("路径.csv")。避免后面出错不需要重新做这之前的步骤!!!

探索特征,开始处理特征矩阵

# 对于Xtrain,先进行描述性统计
Xtrain.describe([0.01,0.05,0.1,0.25,0.5,0.75,0.9,0.99]).T
# 发现特征维度数量变少,因为有些特征类型为object
# 根据现实含义,看看有没有负数异常值,发现没有
# 观察有没有超出常识的数值,也没有

如果发现了异常值,首先要观察,这个异常值的频率,如果异常值只出现了一次,多半是输入错误,直接把异常值删除;如果异常值出现了多次,去跟业务人员沟通(有可能特殊数值有特殊含义),人为造成的错误异常值留着是没有用的;如果异常值占到总数据量的10%左右,可能数据集出现错误,把异常值替换成非异常值,但是非干扰的项,比如用0来进行替换,或者把异常当缺失,以后用均值或众数等方法处理