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

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

常识上来说,我们认为地点肯定是对明天是否会下雨存在影响的。比如说,如果其他信息都不给出,我们只猜测,“伦敦明天是否会下雨”和”北京明天是否会下雨“,我一定会猜测伦敦会下雨,而北京不会,因为伦敦是常年下雨的城市,而北京的气候非常干燥。对澳大利亚这样面积巨大的国家来说,必然存在着不同的城市有着不同的下雨倾向的情况。但尴尬的是,和时间一样,我们输入地点的名字对于算法来说,就是一串字符,"London"和"Beijing"对算法来说,和0,1没有区别。同样,我们的样本中含有49个不同地点,如果做成分类型变量,算法就无法辨别它究竟是否是分类变量。也就是说,我们需要让算法意识到,不同的地点因为气候不同,所以对“明天是否会下雨”有着不同的影响。如果我们能够将地点转换为这个地方的气候的话,我们就可以将不同城市打包到同一个气候中,而同一个气候下反应的降雨情况应该是相似的
由于直接搜索气象站可能无法获得气候信息,所以我们通过爬虫获得澳大利亚主要城市的气候信息、这些城市的经纬度、气象站的经纬度,通过气象站离哪个主要城市最近,来用该城市的气候,决定气象站的气候
在地理上,两个地点之间的距离,由如下公式来进行计算:
d i s t = R × arccos ⁡ ( sin ⁡ ( s l a t ) × sin ⁡ ( e l a t ) + cos ⁡ ( s l a t ) × cos ⁡ ( e l a t ) × cos ⁡ ( s l o n − e l o n ) ) dist=R \times \arccos(\sin (slat)\times \sin (elat)+\cos (slat)\times \cos (elat)\times \cos (slon-elon)) dist=R×arccos(sin(slat)×sin(elat)+cos(slat)×cos(elat)×cos(slonelon))
其中R是地球的半径,6371.01km,arccos是三角反余弦函数,slat是起始地点的纬度,slon是起始地点的经度, elat是结束地点的纬度,elon是结束地点的经度。本质还是计算两点之间的距离。而我们爬取的经纬度,本质其实是角度,所以需要用各种三角函数和弧度公式将角度转换成距离。

澳大利亚主要城市所对应的气候类型数据,并保存在csv文件city_climate.csv当中,每个城市所对应的经纬度,并保存在数据cityll.csv当中

cityll = pd.read_csv(r"D:\ObsidianWorkSpace\SklearnData\cityll.csv",index_col=0)
city_climate = pd.read_csv(r"D:\ObsidianWorkSpace\SklearnData\Cityclimate.csv")

cityll.head() # 每个城市对应的经纬度
---
	City	Latitude	Longitude	Latitudedir	Longitudedir
0	Adelaide	34.9285°	138.6007°	S,	E
1	Albany	35.0275°	117.8840°	S,	E
2	Albury	36.0737°	146.9135°	S,	E

city_climate.head() # 每个城市对应的气候
---
	City	Climate
0	Adelaide	Warm temperate
1	Albany	Mild temperate
2	Albury	Hot dry summer, cool winter

接下来,我们来将这两张表处理成可以使用的样子,首先要去掉cityll中经纬度上带有的度数符号,然后要将两张表合并起来。(这两张表的City是能对应起来的,这是因为爬虫爬取数据的时候设置的)

# 依旧是先处理一个元素然后推广
cityll.loc[0,"Latitude"][:-1] # 对字符串进行切片
---
'34.9285'

float(cityll.loc[0,"Latitude"][:-1])
---
34.9285

cityll['Latitudenum'] = cityll['Latitude'].apply(lambda x:float(x[:-1]))
cityll['Longitudenum'] = cityll['Longitude'].apply(lambda x:float(x[:-1]))

# 这里度数可能是南纬北纬,东经西经,所以我们需要确定是否相同
cityll.loc[:,'Latitudedir'].value_counts()
---
S,    100
Name: Latitudedir, dtype: int64

cityll.loc[:,'Longitudedir'].value_counts()
---
E    100
Name: Longitudedir, dtype: int64
# 发现相同,因此不需要担心,所以经纬度的方向我们可以舍弃了

citylld = cityll.iloc[:,[0,5,6]]
citylld.head()
---
	City	Latitudenum	Longitudenum
0	Adelaide	34.9285	138.6007
1	Albany	35.0275	117.8840
2	Albury	36.0737	146.9135

# 将city_climate中的气候添加到citylld中
citylld['climate'] = city_climate.iloc[:,-1]
# 这两个表在制作的时候City就是能对应起来的
# 如果不能对应起来,需要使用map

citylld.head() # 澳大利亚常见城市的经纬度
---
	City	Latitudenum	Longitudenum	climate
0	Adelaide	34.9285	138.6007	Warm temperate
1	Albany	35.0275	117.8840	Mild temperate
2	Albury	36.0737	146.9135	Hot dry summer, cool winter

citylld.loc[:,'climate'].value_counts()
---
Hot dry summer, cool winter          24
Hot dry summer, warm winter          18
Warm temperate                       18
High humidity summer, warm winter    17
Cool temperate                        9
Mild temperate                        9
Warm humid summer, mild winter        5
Name: climate, dtype: int64

爬取训练集中所有的地点所对应的经纬度,并且保存在一个csv文件samplecity.csv中

samplecity = pd.read_csv(r'D:\ObsidianWorkSpace\SklearnData\samplecity.csv',index_col=0)
samplecity.head()
---
	City	Latitude	Longitude	Latitudedir	Longitudedir
0	Canberra	35.2809°	149.1300°	S,	E
1	Sydney	33.8688°	151.2093°	S,	E
2	Perth	31.9505°	115.8605°	S,	E

# 取度数,转float
samplecity['Latitudenum'] = samplecity['Latitude'].apply(lambda x:float(x[:-1]))
samplecity['Longitudenum'] = samplecity['Longitude'].apply(lambda x:float(x[:-1]))
samplecityd = samplecity.iloc[:,[0,5,6]]
samplecityd.head() # 样本城市的经纬度
---
	City	Latitudenum	Longitudenum
0	Canberra	35.2809	149.1300
1	Sydney	33.8688	151.2093
2	Perth	31.9505	115.8605

# 已知经纬度计算两点的距离
from math import radians, sin, cos, acos

# 我们已知的是角度,但是三角函数计算的时候需要弧度
citylld.loc[:,'slat'] = citylld.iloc[:,1].apply(lambda x:radians(x))
citylld.loc[:,'slon'] = citylld.iloc[:,2].apply(lambda x:radians(x))
samplecityd.loc[:,'elat'] = samplecityd.iloc[:,1].apply(lambda x:radians(x))
samplecityd.loc[:,'elon'] = samplecityd.iloc[:,2].apply(lambda x:radians(x))

import sys # 这个我不知道是干啥的

for i in range(samplecityd.shape[0]):
    slat = citylld.loc[:,'slat']
    slon = citylld.loc[:,'slon']
    elat = samplecityd.loc[i,'elat']
    elon = samplecityd.loc[i,'elon']
    dist = 6371.01 * np.arccos(np.sin(slat) * np.sin(elat) + 
                              np.cos(slat) * np.cos(elat) * np.cos(slon.values - elon)) # 计算到每个已知城市的距离
    city_index = np.argsort(dist)[0]
    # 每次计算后,取距离最近的城市,然后将最近的城市和城市对应的气候都匹配到samplecityd中
    samplecityd.loc[i,"closest_city"] = citylld.loc[city_index,"City"]
    # 用于验证是否编写有问题,在地图上查,如果City和closest_city距离很远可能上面编写有问题
    samplecityd.loc[i,'climate'] = citylld.loc[city_index,"climate"]

这里说一下代码中的这一行

dist = 6371.01 * np.arccos(np.sin(slat) * np.sin(elat) + 
						  np.cos(slat) * np.cos(elat) * np.cos(slon.values - elon))
np.array([1,2])*np.array([3,4]) # 一维数组相乘等于对应元素相乘
---
array([3, 8])

说一下np.argsort

np.argsort(np.array([1,2,4,3])) # 返回索引列表,返回列表的第一个元素就是之前输入列表的最小值的索引
---
array([0, 1, 3, 2], dtype=int64)
samplecityd.head()
---
	City	Latitudenum	Longitudenum	elat	elon	closest_city	climate
0	Canberra	35.2809	149.1300	0.615768	2.602810	Canberra	Cool temperate
1	Sydney	33.8688	151.2093	0.591122	2.639100	Sydney	Warm temperate
2	Perth	31.9505	115.8605	0.557641	2.022147	Perth	Warm temperate

localfinal = samplecityd.iloc[:,[0,-1]]
localfinal.head()
---
	City	climate
0	Canberra	Cool temperate
1	Sydney	Warm temperate
2	Perth	Warm temperate

localfinal.columns = ['Location','Climate']
localfinal = localfinal.set_index(keys='Location')
# 在这里设定Localfinal的索引为地点,是为了之后进行map匹配
localfinal.head()
---
			Climate
Location	
Canberra	Cool temperate
Sydney	Warm temperate
Perth	Warm temperate

Xtrain['Location'] = Xtrain['Location'].map(localfinal.iloc[:,0])
# 这里map中的localfinal.iloc[:,0]可以看做是一个字典,键是localfinal的键,值是localfinal.iloc[:,0]
# 从Xtrain['Location']取出键,在localfinal.iloc[:,0]中索引,找到对应值,也就是将气象站的名字替换成对应城市的气候
Xtrain['Location'].head()
---
0    High humidity summer, warm winter
1                    Cool temperate   
2                    Mild temperate   
3                    Mild temperate   
4          Hot dry summer, cool winter
Name: Location, dtype: object
# 观察上面的值,我们发现里面有逗号,两端还可能有空格,我们要去掉逗号和空格

Xtrain['Location'] = Xtrain['Location'].apply(lambda x:re.sub(',','',x.strip()))
# re.sub(想要替换的值,想要替换成什么,谁被替换)
# 做哑变量的时候就不能有逗号
# x.strip()去掉字符串两端的空格
Xtrain = Xtrain.rename(columns={"Location":'Climate'})
Xtest = Xtest.rename(columns={"Location":'Climate'})

到这里,地点就处理完毕了。其实,我们还没有将这个特征转化为数字,即还没有对它进行编码。我们稍后和其他的分类型变量一起来编码。

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