视频作者:菜菜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所在列进行特征创造,但是首先保证该特征没有空值,或者将空值复制过去
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'})