【菜菜的sklearn课堂笔记】支持向量机-SVC真实数据案例:预测明天是否会下雨-处理困难特征:日期

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

我们对时间的处理主要是如何思考时间如何影响标签,以及怎样转化成影响标签的新变量

首先我们考虑日期能不能被直接用作一个特征

type(Xtrain.iloc[0,0]) # 发现日期属于字符串
---
str

# 我们现在拥有的日期特征,是连续型特征,还是分类特征
# 日期可以看做一年分了365类的分类型变量
# 判断日期是否有重复
Xtrain.iloc[:,0].value_counts().head() # 我们可以知道日期不是一天挨着一天的连续型变量,日期有重复
# 重复的原因可能是不同Location上相似的时间,下面会验证这种想法是正确的
----
2014-05-16    6
2015-10-12    6
2015-07-03    6
2014-03-12    5
2011-09-04    5
Name: Date, dtype: int64

# 某一年的某一天不会倾向于会下雨或者倾向于不会下雨
# 不是日期影响了下雨与否,反而更多的是这一天的光照时间,湿度等这些因素影响了是否下雨
# 光看日期,其实感觉它对我们的判断并无直接影响

单独说一下value_counts()和count()

value_counts()

import numpy as np
import pandas as pd

a = pd.DataFrame(np.random.randint(0,2,(5,2)))
a
---
	0	1
0	1	1
1	1	0
2	0	1
3	0	1
4	1	0

type(a[0]) #Series对象
---
pandas.core.series.Series

a[0].value_counts() # value_counts()的对必须是Series,而不是DataFrame或ndarray
# 作用是计算某个值在Series中出现的次数,索引是值,后面是次数
# 返回的依旧是Series对象
---
1    3
0    2
Name: 0, dtype: int64

count()

a.loc[3,1]=np.nan
a.count(1) # 这里count()的对象是Series或者DataFrame,返回结果是非空元素个数
# 对于DataFrame可以指定行或列,count(1)就是计算每行非空元素个数,count(0)就是对列
# 注意是元素个数,不能指定某个元素个数,也不是加和
---
0    2
1    2
2    2
3    1
4    2
dtype: int64

b = pd.Series([1,2,3,4])
b.count()
---
4
# 因此我们一般a[0].value_counts().count()这种用法可以认为是计算某一个特征中出现了多少个取值
Xtrain.iloc[:,0].value_counts().count()
# 如果我们把它当做分类变量处理,类别太多
# 如果换成数值型,计算机无法意识到这是日期,会被直接当做连续型变量,算法会认为它是一系列1-3000左右的数字,不会意识到这是日期。也就是说我们认为的分类型变量算法会看做连续型变量
# 如果做成哑变量,特征维度会爆炸
# 如果当连续型,就如上面说到的算法会认为它是一系列1-3000左右的数字,不会意识到这是日期,即没有加和等性质
---
2141

经过上面的考虑我们可以得出一个结论,在本例条件下,日期不能直接使用,必须要进行特征创造等方法

日期必然是和我们的结果有关的,它会从两个角度来影响我们的标签:

  • 昨天的天气可能会影响今天的天气,而今天的天气又可能会影响明天的天气。也就是说,随着日期的逐渐改变,样本是会受到上一个样本的影响的。但是对于算法来说,普通的算法是无法捕捉到样本与样本之间的联系的,我们的算法捕捉的是样本的每个特征与标签之间的联系(即列与列之间的联系),而无法捕捉样本与样本之间的联系(行与行的联系)。
    要让算法理解上一个样本的标签可能会影响下一个样本的标签,我们必须使用时间序列分析。时间序列分析是指将同一统计指标的数值按其发生的时间先后顺序排列而成的数列。时间序列分析的主要目的是根据已有的历史数据对未来进行预测。然而,(据我所知)时间序列只能在单调的,唯一的时间上运行,即一次只能够对一个地点进行预测,不能够实现一次性预测多个地点,除非进行循环。而我们的时间数据本身,不是单调的,也不是唯一的,经过抽样之后,甚至连连续的都不是了,我们的时间是每个混杂在多个地点中,每个地点上的一小段时间。如何使用时间序列来处理这个问题,就会变得复杂。
  • 既然算法处理的是列与列之间的关系,我们可以把”今天的天气会影响明天的天气“这个指标转换成一个特征
    我们观察到,我们的特征中有一列叫做“Rainfall",这是表示当前日期当前地区下的降雨量,换句话说,也就是”今天的降雨量“。凭常识我们认为,今天是否下雨,应该会影响明天是否下雨,比如有的地方可能就有这样的气候,一旦下雨就连着下很多天,也有可能有的地方的气候就是一场暴雨来得快去的快。因此,我们可以将时间对气候的连续影响,转换为”今天是否下雨“这个特征,巧妙地将样本对应标签之间的联系,转换成是特征与标签之间的联系了。

创造特征今天是否下雨

# 我们决定使用Rainfall所在列进行特征创造,但是首先保证该特征没有空值,或者将空值复制过去
Xtrain["Rainfall"].head(20)
---
0      0.0
1      0.0
2      0.0
……
17     0.0
18    35.2
19     0.0
Name: Rainfall, dtype: float64

Xtrain["Rainfall"].isnull().sum()
# 发现有33个空值
# 可以认为没下雨,因为没下雨是多数时间;或者不动,把空值复制过去
---
33

# 我们假定,认为Rainfall >= 1可以算作下雨了,Rainfall < 1算作没下雨,空值不动复制过去
Xtrain.loc[Xtrain.loc[:,'Rainfall'] >= 1,'Raintoday'] = 'Yes'
Xtrain.loc[Xtrain.loc[:,'Rainfall'] < 1,'Raintoday'] = 'No'
Xtrain.loc[Xtrain.loc[:,'Rainfall'] == np.nan,'Raintoday'] = np.nan
Xtest.loc[Xtest.loc[:,'Rainfall'] >= 1,'Raintoday'] = 'Yes'
Xtest.loc[Xtest.loc[:,'Rainfall'] < 1,'Raintoday'] = 'No'
Xtest.loc[Xtest.loc[:,'Rainfall'] == np.nan,'Raintoday'] = np.nan

Xtrain.head() # 多了一列Raintoday
---
5 rows × 22 columns

实际上面我们并不是对日期特征本身进行操作,下面我们对日期进行操作
日期本身并不影响天气,但是日期所在的月份和季节其实是影响天气的,如果任选梅雨季节的某一天,那明天下雨的可能性必然比非梅雨季节的那一天要大。虽然我们无法让机器学习体会不同月份是什么季节,但是我们可以对不同月份进行分组,算法可以通过训练感受到,“这个月或者这个季节更容易下雨”。因此,我们可以将月份或者季节提取出来,作为一个特征使用,而舍弃掉具体的日期。如此,我们又可以创造第二个特征,月份"Month"。

之前我们说对每一个日期进行分类算法会认为它是一系列1-3000左右的数字,不会意识到这是日期,因为取值太多了;现在对于月份,只有12个,算法可以意识到这是分类型变量
一般小于25个取值算法能意识到该变量是分类型变量

# 操作一整列数据之前,我们可以先操作其中一个数据,然后推广到整列
Xtrain.loc[0,"Date"]
---
'2015-08-24'

Xtrain.loc[0,"Date"].split('-') # 注意此时列表里面是str,而不是int
---
['2015', '08', '24']

int(Xtrain.loc[0,"Date"].split('-')[1])
# 显然这个8就是我们想要的月份
---
8

# 推广到整列
Xtrain["Date"] = Xtrain["Date"].apply(lambda x:int(x.split('-')[1]))
# apply是对DataFrame上的某一列进行处理的一个函数
# lambda x匿名函数,在DataFrame上这一列中的每一行执行冒号后的命令
# 注意这里lambda后面的x是一个列向量,而不是一个元素的取值

Xtrain["Date"].value_counts()
---
3     334
5     324
7     316
9     302
6     302
1     300
11    299
10    282
4     265
2     264
12    259
8     253
Name: Date, dtype: int64

替换完毕后,我们需要修改列的名称。之前修改列的名称的方法Xtrain.columns = [],但现在有22列,我们只想要修改其中的一个名称,因此我们使用rename(columns=字典)的方法

Xtrain = Xtrain.rename(columns={'Date':'Month'})
# 键是想要修改的列现在的名字,值是想要改为的名字
# rename函数也可以改行索引,使用index=

对Xtest执行相同的操作

Xtest["Date"] = Xtest["Date"].apply(lambda x:int(x.split('-')[1]))
Xtest = Xtest.rename(columns={'Date':'Month'})

你可能感兴趣的:(菜菜的sklearn课堂,sklearn,支持向量机,python,算法)