机器学习sklearn-支持向量机实例(预测天气)

机器学习sklearn-支持向量机实例(预测天气),第1张

机器学习sklearn-支持向量机实例(预测天气)

目录

数据预处理

完整代码


数据预处理

导入数据查看相关信息

 

 

 

在现实中,我们会先分训练集和测试集,再开始进行数据预处理。这是由于,测试集在现实中往往是不可获得的,或者被假设为是不可获得的,我们不希望我们建模的任何过程受到测试集数据的影响,否则的话,就相当于提前告诉了模型一部分预测的答案。 完整代码
import pandas as pd
import numpy as np
import sys
import re
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OrdinalEncoder
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import confusion_matrix as CM
import matplotlib.pyplot as plt
from sklearn.preprocessing import LabelEncoder
from sklearn.impute import SimpleImputer
from math import radians, sin, cos, acos
from time import time
import datetime
from sklearn.svm import SVC
from sklearn.model_selection import cross_val_score
from sklearn.metrics import roc_auc_score, recall_score

weather=pd.read_csv('weatherAUS5000.csv',index_col=0)
# print(weather.head())
# print(weather.info())

#分离标签和特征矩阵
X=weather.iloc[:,:-1]
y=weather.iloc[:,-1]
#查看缺失值比例 针对不同的缺失值 制定不同的填补策略
# print(y.isnull().sum())
# print(X.isnull().mean())
#查看标签类别
# print(np.unique(y))

#划分训练集和测试集
Xtrain, Xtest, Ytrain, Ytest = train_test_split(X,y,test_size=0.3,random_state=420)
#恢复索引
for i in [Xtrain, Xtest, Ytrain, Ytest]:
    i.index=range(i.shape[0])

#查看是否存在样本不均衡
# print(Ytrain.value_counts())
# print(Ytrain.value_counts())
#有轻微的样本不均衡问题 No:Yes 在3.4左右

#给标签编码
encoder=LabelEncoder().fit(Ytrain)
Ytrain=pd.Dataframe(encoder.transform(Ytrain))
Ytest=pd.Dataframe(encoder.transform(Ytest))

#描述性统计
# print(Xtrain.describe([0.01,0.05,0.1,0.25,0.5,0.75,0.9,0.99]).T)
# print(Xtest.describe([0.01,0.05,0.1,0.25,0.5,0.75,0.9,0.99]).T)

#处理时间
""" 
    没有经过严格的验证表明日期时间和明天是否下雨无关
    最好不要将日期这一特征删除
    时间不是连续型变量 且分类后为2000多种过于庞大
    同一天有不同地方的数据
    换一种想法 我们可以认为创造日期和是否下雨的关系
    把今天的天气是否影响明天下雨创建一个特征
    通常而言,今天下雨后,明天也下雨的概率会更大一点
"""
#根据今天的下雨量还判断今天是否下雨并创建新的特征
Xtrain.loc[Xtrain['Rainfall']>=1,'RainToday']='Yes'
Xtrain.loc[Xtrain["Rainfall"] < 1,"RainToday"] = "No"
Xtrain.loc[Xtrain["Rainfall"] == np.nan,"RainToday"] = np.nan

Xtest.loc[Xtest["Rainfall"] >= 1,"RainToday"] = "Yes"
Xtest.loc[Xtest["Rainfall"] < 1,"RainToday"] = "No"
Xtest.loc[Xtest["Rainfall"] == np.nan,"RainToday"] = np.nan

# print(Xtrain.head())
# print(Xtest.head())

"""
    创建当天是否下雨之后
    考虑降雨和所在月份或者季节存在一定的联系
    在这里,我们创造出有关月份的特征
"""

#取出月份并保存
#apply是对dataframe上某一列上的数据进行处理
Xtrain['Date']=Xtrain['Date'].apply(lambda x:int(x.split('-')[1]))
#替换完毕后,我们需要修改列的名称
#rename是比较少有的,可以用来修改单个列名的函数
#我们通常都直接使用 df.columns = 某个列表 这样的形式来一次修改所有的列名
#但rename允许我们只修改某个单独的列
Xtrain = Xtrain.rename(columns={"Date":"Month"})

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

# print(Xtrain.head())
# print(Xtest.head())

#处理地区
"""
    数据共有49个地区
    对于澳大利亚一个国家来说
    不同的地区,可以划分为不同的气候带
    不同的气候带会有不同的降雨概率
    location数据是气象站名字,而非城市名字
    因此我们需要经纬度来找到所属的城市
"""

#导入气候数据和经纬度数据
cityll = pd.read_csv("cityll.csv",index_col=0) #经纬度数据
city_climate = pd.read_csv("Cityclimate.csv") #气候数据
#对经纬度数据做预处理
#去掉度数
cityll["Latitudenum"] = cityll["Latitude"].apply(lambda x:float(x[:-1]))
cityll["Longitudenum"] = cityll["Longitude"].apply(lambda x:float(x[:-1]))
# print(cityll.head())
# print(cityll.info())

#查看城市方向
# print(cityll.loc[:,'Longitudedir'].value_counts())
# print(cityll.loc[:,'Latitudedir'].value_counts())
#澳大利亚所有城市都在东南方向 所以该特征可以舍去
citylld = cityll.iloc[:,[0,5,6]]#取出城市名称和经纬度

#将city_climate中的气候添加到我们的citylld中
citylld["climate"] = city_climate.iloc[:,-1]#注意此时两个文件内部城市的顺序是一样的 不然须进行map
# print(citylld.head())

#读取所以地点对应的经纬度来计算距离
samplecity = pd.read_csv("samplecity.csv",index_col=0)
#去掉°符号
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]]
#计算距离来判断气候站在哪座城市
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))

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"]
    samplecityd.loc[i,"climate"] = citylld.loc[city_index,"climate"] #查看最后的结果,需要检查城市匹配是否基本正确

# print(samplecityd.head())

#确认无误后,取出样本城市所对应的气候,并保存
locafinal = samplecityd.iloc[:,[0,-1]]
locafinal.columns = ["Location","Climate"]
#在这里设定locafinal的索引为地点,是为了之后进行map的匹配
locafinal = locafinal.set_index(keys="Location")

#使用气候替换原有的气象站
#apply之前将城市替换为对应气候
#之后是删去气候里的空格和逗号
Xtrain["Location"] = Xtrain["Location"].map(locafinal.iloc[:,0]).apply(lambda
                                                    x:re.sub(",","",x.strip()))
Xtest["Location"] = Xtest["Location"].map(locafinal.iloc[:,0]).apply(lambda
                                                    x:re.sub(",","",x.strip()))

#修改特征内容之后,我们使用新列名“Climate”来替换之前的列名“Location”
#注意这个命令一旦执行之后,就再没有列"Location"了,使用索引时要特别注意
Xtrain = Xtrain.rename(columns={"Location":"Climate"})
Xtest = Xtest.rename(columns={"Location":"Climate"})
# print(Xtrain.head())
# print(Xtest.head())

#处理缺失值
#查看缺失情况
# print(Xtrain.isnull().mean())

#找出分类特征所在的列索引
cate=Xtrain.columns[Xtrain.dtypes=='object'].tolist()
#除了特征类型为"object"的特征们,还有虽然用数字表示,但是本质为分类型特征的云层遮蔽程度
cloud=["Cloud9am","Cloud3pm"]
cate=cate+cloud
# print(cate)
#使用众数填补分类型特征
si=SimpleImputer(missing_values=np.nan,strategy='most_frequent')
#训练集数据量更大,使用训练集来填补训练集和测试集上众数填补分类特征的缺失值
si.fit(Xtrain.loc[:,cate])#训练模型
#然后我们用训练集中的众数来同时填补训练集和测试集
Xtrain.loc[:,cate] = si.transform(Xtrain.loc[:,cate])
Xtest.loc[:,cate] = si.transform(Xtest.loc[:,cate])

#查看分类型特征是否依然存在缺失值
# print(Xtrain.loc[:,cate].isnull().mean())
# print(Xtest.loc[:,cate].isnull().mean())

#将分类型变量编码为数字
#先做普通编码 如果模型效果不好再改为哑变量
#哑变量特征太多 对支持向量机不友好
oe=OrdinalEncoder()
oe=oe.fit(Xtrain.loc[:,cate])
#用训练集的编码结果来编码训练和测试特征矩阵
#在这里如果测试特征矩阵报错,就说明测试集中出现了训练集中从未见过的类别
Xtrain.loc[:,cate] = oe.transform(Xtrain.loc[:,cate])
Xtest.loc[:,cate] = oe.transform(Xtest.loc[:,cate])

#检查编码效果
# print(Xtrain.head())
# print(Xtest.head())

#处理连续型变量,连续型变量一般已经是数字,不需要进行编码转换
#提取所有列
col=Xtrain.columns.tolist()
#去除离散型变量
for i in cate:
    col.remove(i)
#使用均值填补缺失值
impmean=SimpleImputer(missing_values=np.nan,strategy='mean')
#使用训练集来fit模型
impmean.fit(Xtrain.loc[:,col])
#分别在训练集和测试集上进行均值填补
Xtrain.loc[:,col] = impmean.transform(Xtrain.loc[:,col])
Xtest.loc[:,col] = impmean.transform(Xtest.loc[:,col])

#查看最终填补效果
# print(Xtrain.isnull().mean())
# print(Xtest.isnull().mean())

#无量纲化的处理对支持向量机很重要
#进行标准化 分类变量编码以后不需要标准化
#月份不需要标准化
col.remove("Month")
ss=StandardScaler()
ss.fit(Xtrain.loc[:,col])
Xtrain.loc[:,col] = ss.transform(Xtrain.loc[:,col])
Xtest.loc[:,col] = ss.transform(Xtest.loc[:,col])
#检测标准化是否成功
# print(Xtrain.head())
# print(Xtest.head())

#对标签进行降维 dataframe都是二维数据
Ytrain = Ytrain.iloc[:,0].ravel()
Ytest = Ytest.iloc[:,0].ravel()
#建模选择自然是我们的支持向量机SVC,首先用核函数的学习曲线来选择核函数
#我们希望同时观察,精确性,recall以及AUC分数
# times = time() #因为SVM是计算量很大的模型,所以我们需要时刻监控我们的模型运行时间
# for kernel in ["linear","poly","rbf","sigmoid"]:
#     clf = SVC(kernel = kernel,
#               gamma="auto",degree = 1,
#               cache_size = 5000).fit(Xtrain, Ytrain)
#     result = clf.predict(Xtest)#获取预测结果
#     score = clf.score(Xtest,Ytest)#打分:accurancy
#     recall = recall_score(Ytest, result)
#使用距离来做置信度
#     auc = roc_auc_score(Ytest, clf.decision_function(Xtest))
    # print("%s 's testing accuracy %f, recall is %f', auc is %f" % (kernel, score, recall, auc))
    # print(datetime.datetime.fromtimestamp(time() - times).strftime("%M:%S:%f"))
"""
    linear 's testing accuracy 0.844000, recall is 0.469388', auc is 0.869029
    00:04:531012
    poly 's testing accuracy 0.840667, recall is 0.457726', auc is 0.868157
    00:05:143344
    rbf 's testing accuracy 0.813333, recall is 0.306122', auc is 0.814873
    00:07:336713
    sigmoid 's testing accuracy 0.655333, recall is 0.154519', auc is 0.437308
    00:07:999905
"""

#观察结果 线性核函数的效果最佳,可以断定数据是线性的
#接下来就根据不同的目标来对模型其他参数进行调整

""" 如果追求更好的recall
    即不计代价捕捉少数类
    调整权重参数为balanced
    clf = SVC(kernel = kernel,gamma="auto"
    ,degree = 1,cache_size = 5000,
    class_weight = "balanced").fit(Xtrain, Ytrain)
    
    clf = SVC(kernel = "linear",gamma="auto"
    ,cache_size = 5000
    ,class_weight = {1:10} #注意,这里写的其实是,类别1:10,隐藏了类别0:1这个比例
    ).fit(Xtrain, Ytrain)
"""

#追求更高的准确率
#查看样本不均衡问题是否严重
valuec=pd.Series(Ytest).value_counts()
# print(valuec[0]/valuec.sum())
# 0.7713333333333333

#查看模型的特异度
# clf = SVC(kernel = "linear",gamma="auto",cache_size = 5000).fit(Xtrain, Ytrain)
# result = clf.predict(Xtest)
# cm = CM(Ytest,result,labels=(1,0))
# specificity = cm[1,1]/cm[1,:].sum()
# print(specificity)
#0.9550561797752809
#几乎所有的0都被判断正确了,还有不少1也被判断正确了
#此时过大的调整权重参数,只会导致判错更多的0
#因此我们可以细化权重的范围 慢慢调整

irange = np.linspace(0.01,0.05,10)
for i in irange:
    times = time()
    clf = SVC(kernel = "linear"
              ,gamma="auto"
              ,cache_size = 5000
              ,class_weight = {1:1+i}).fit(Xtrain, Ytrain)
    result = clf.predict(Xtest)
    score = clf.score(Xtest,Ytest)
    recall = recall_score(Ytest, result)
    auc = roc_auc_score(Ytest,clf.decision_function(Xtest))
    print("under ratio 1:%f testing accuracy %f, recall is %f', auc is %f" % (1+i,score,recall,auc))
    print(datetime.datetime.fromtimestamp(time()-times).strftime("%M:%S:%f"))

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5711988.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-18

发表评论

登录后才能评论

评论列表(0条)

保存