文章目录
前言
依然是记录一次我的近期作业,这个做了一天半才做完,昨天通宵去拟合函数结果还是不理想,耽误了太多时间。主要原因还是昨天取的特征值太少了导致一直欠拟合,当然数据的分布也确实不太友好,先来看看这次的任务背景和任务要求。
然后需要我们计算十二个指标
任务流程
现在熟悉了任务背景和流程要求,就开始动手。(其实这个案例前半部分是教我们如何用循环去得到指标的,这部分我就不贴了)
开始动手
1.导入数据,查看并且计算指标
import pandas as pd
import numpy as np
import math
import warnings
warnings.filterwarnings("ignore")
A=pd.read_excel('./第9次作业 已结束项目任务数据.xls')
B=pd.read_excel('./第9次作业 会员信息数据.xlsx')
A.info()
A.head()
B.info()
B.head()
数据集就是这个样子,每一个属性的意义也很清楚,数据本身其实也很干净,所以我就没有进行数据预处理直接去计算要求的指标了。
#将B转换为时间序列
B['预订任务开始时间']= pd.to_datetime(B['预订任务开始时间'],format = '%H:%M:%S')
B.info()
B.head()
# 开始得到Z1-Z12
Z=np.zeros((len(A),12))
for q in range(len(A)):
A_Wq=A.iloc[q,1]
A_Jq=A.iloc[q,2]
D1=np.zeros((len(A)))
D2=np.zeros((len(B)))
for t in range(len(A)):
A_Wt=A.iloc[t,1]
A_Jt=A.iloc[t,2]
dt=111.19*math.sqrt((A_Wq-A_Wt)**2+(A_Jq-A_Jt)**2*math.cos((A_Wq+A_Wt)*math.pi/180)**2)
D1[t]=dt
for k in range(len(B)):
B_Wk=B.iloc[k,1]
B_Jk=B.iloc[k,2]
dk=111.19*math.sqrt((A_Wq-B_Wk)**2+(A_Jq-B_Jk)**2*math.cos((A_Wq+B_Wk)*math.pi/180)**2)
D2[k]=dk
Z1=len(D1[D1<=5])-1 #5公里内其他任务量
Z2=A.iloc[D1<=5,[3]].mean()[0] #5公里内的平均价格
Z3=B.iloc[D2<=5,[3]].sum()[0] #5公里内可预订任务量
Z4=B.iloc[D2<=5,[3,5]].sum()[1]/len(D2[D2<=5]) #5公里内信誉平均值
Z5=len(D2[D2<=5]) #5公里内会员个数
#下面是不同时间段内的任务量
Z6=B.iloc[D2<=5,[3,4]][(B['预订任务开始时间']==pd.to_datetime('06:30:00',format='%H:%M:%S'))]['预订任务限额'].sum()
Z7=B.iloc[D2<=5,[3,4]][(B['预订任务开始时间']>=pd.to_datetime('06:33:00',format='%H:%M:%S'))&(B['预订任务开始时间']<=pd.to_datetime('06:45:00',format='%H:%M:%S'))]['预订任务限额'].sum()
Z8=B.iloc[D2<=5,[3,4]][(B['预订任务开始时间']>=pd.to_datetime('06:48:00',format='%H:%M:%S'))&(B['预订任务开始时间']<=pd.to_datetime('07:03:00',format='%H:%M:%S'))]['预订任务限额'].sum()
Z9=B.iloc[D2<=5,[3,4]][(B['预订任务开始时间']>=pd.to_datetime('07:06:00',format='%H:%M:%S'))&(B['预订任务开始时间']<=pd.to_datetime('07:21:00',format='%H:%M:%S'))]['预订任务限额'].sum()
Z10=B.iloc[D2<=5,[3,4]][(B['预订任务开始时间']>=pd.to_datetime('07:24:00',format='%H:%M:%S'))&(B['预订任务开始时间']<=pd.to_datetime('07:39:00',format='%H:%M:%S'))]['预订任务限额'].sum()
Z11=B.iloc[D2<=5,[3,4]][(B['预订任务开始时间']>=pd.to_datetime('07:42:00',format='%H:%M:%S'))&(B['预订任务开始时间']<=pd.to_datetime('07:57:00',format='%H:%M:%S'))]['预订任务限额'].sum()
Z12=B.iloc[D2<=5,[3,4]][(B['预订任务开始时间']==pd.to_datetime('08:00:00',format='%H:%M:%S'))]['预订任务限额'].sum()
Z[q,0]=Z1
Z[q,1]=Z2
Z[q,2]=Z3
Z[q,3]=Z4
Z[q,4]=Z5
Z[q,5]=Z6
Z[q,6]=Z7
Z[q,7]=Z8
Z[q,8]=Z9
Z[q,9]=Z10
Z[q,10]=Z11
Z[q,11]=Z12
data=pd.DataFrame(Z)
print(data.head())
data.to_csv("第九次作业指标.csv",index=False,encoding="utf-8")
对于时间的截取我也不太熟悉,所以用的是这种比较笨的截取方法。然后把得到的数据保存到csv文件,避免我们每次都要算一次这个。(因为我们后面计算有可能会导致电脑卡死然后restart kernel,所以保存一下比较好)
2.导入我们得到的指标,并且进行主成分分析
data=pd.read_csv('./第九次作业指标.csv')
data.info()
data.head()
然后我后面报错,发现有缺失值,所以先来填补一次
# 填补缺失值
data.fillna(0,inplace=True)
data.astype(float)
data.info()
data.head()
相关性分析
# 进行相关性计算,并可视化一下
import matplotlib.pyplot as plt
import seaborn as sns
plt.rcParams['font.family']='FangSong'
plt.rcParams['axes.unicode_minus']=False
sns.pairplot(data)
plt.show()
sns.heatmap(data.corr())
plt.show()
主成分分析
# 进行主成分分析,使得累计贡献率达到90%以上
from sklearn.decomposition import PCA
res=[]
for i in range(1,10):
pca=PCA(n_components=i)
pca.fit(data)
res.append(pca.explained_variance_ratio_.sum())
plt.plot([i for i in range(1,10)],res)
plt.title("不同主成分数目下的累计贡献率")
plt.xlabel("主成分数目")
plt.ylabel("贡献率")
plt.show()
然后我也试了一下让它自己选择降维数
#让他自己选择数目看下是否符合要求
pca=PCA(n_components='mle')
pca.fit(data)
print("主成分数目为:",pca.n_components_)
print("累计贡献率为:",pca.explained_variance_ratio_.sum())
print("特征值为:",pca.get_covariance())
发现11就行(为了后面提高拟合效果,我这里尽量选多点)
#由上面的贡献率来看取11个主成分就好
pca=PCA(n_components=11)
trans_data=pca.fit_transform(data)
print(pca.explained_variance_ratio_.sum())
# 各个主成分的贡献率可视化
plt.figure()
plt.bar([i for i in range(trans_data.shape[1])],pca.explained_variance_ratio_)
plt.title("各个主成分的贡献率")
plt.xlabel("主成分")
plt.ylabel("贡献率")
plt.show()
print("主成分数目为11时特征向量为:",pca.components_)
特征向量如下,由特征向量就能得到主成分表达式了(矩阵相乘)
3.添加主成分数据,进行拟合
# 然后我们把得到的主成分添加到已结束任务数据的表中
trans_data=pd.DataFrame(trans_data,
columns=['主成分1','主成分2','主成分3','主成分4','主成分5','主成分6','主成分7','主成分8','主成分9','主成分10','主成分11'])
trans_data.head()
data=pd.merge(A,trans_data,how='left',left_index=True,right_index=True)
finished=data[data['任务执行情况']==1]
finished.head()
#以主成分为自变量,任务标价为因变量探索是否为线性关系
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
X=finished[['主成分1','主成分2','主成分3','主成分4','主成分5','主成分6','主成分7','主成分8','主成分9','主成分10','主成分11']]
Y=finished['任务标价']
sns.jointplot(X['主成分1'],Y,kind='reg')
sns.jointplot(X['主成分2'],Y,kind='reg')
sns.jointplot(X['主成分3'],Y,kind='reg')
sns.jointplot(X['主成分4'],Y,kind='reg')
sns.jointplot(X['主成分5'],Y,kind='reg')
plt.show()
由图看得出其实并不是线性关系,然后就有了我下面的尝试
# 先用多元回归拟合试试
#对X标准化处理
scaler=StandardScaler().fit(X)
X=scaler.transform(X)
X_train, X_test, y_train, y_test = train_test_split(X,Y, test_size=0.2, random_state=2)
from sklearn.metrics import r2_score
linreg = LinearRegression()
linreg.fit(X_train,y_train)
y_pred = linreg.predict(X_test)
print(linreg.score(X_test,y_test))
# 可视化看看测试集拟合效果
plt.figure()
plt.plot([i for i in range(len(X_test))],y_pred,label='拟合曲线')
plt.plot([i for i in range(len(X_test))],y_test,label='真实曲线')
plt.title("测试集拟合效果")
plt.legend()
plt.show()
#增加高次项再看看拟合效果
quadratic_fearurizer = PolynomialFeatures(degree=2)
X_train_quadratic = quadratic_fearurizer.fit_transform(X_train)
X_test_quadratic = quadratic_fearurizer.transform(X_test)
linreg = LinearRegression()
linreg.fit(X_train_quadratic,y_train)
y_train_pred=linreg.predict(X_train_quadratic)
y_pred = linreg.predict(X_test_quadratic)
print(linreg.score(X_train_quadratic,y_train))
print(linreg.score(X_test_quadratic,y_test))
# 可视化看看训练集拟合效果
plt.figure()
plt.plot([i for i in range(len(X_train))],y_train_pred,label='拟合曲线')
plt.plot([i for i in range(len(X_train))],y_train,label='真实曲线')
plt.title("训练集拟合效果")
plt.legend()
plt.show()
# 可视化看看测试集拟合效果
plt.figure()
plt.plot([i for i in range(len(X_test))],y_pred,label='拟合曲线')
plt.plot([i for i in range(len(X_test))],y_test,label='真实曲线')
plt.title("测试集拟合效果")
plt.legend()
plt.show()
添加了二次项后拟合的效果
不太理想,再试试其他的
#试试mlp
from sklearn.neural_network import MLPRegressor
para_dict ={'alpha':10**-np.arange(-7,0),'hidden_layer_sizes':[10,20,50,100,150,200]}
model_mlp = MLPRegressor(
solver='lbfgs', alpha=1e-5,hidden_layer_sizes=(5,10), random_state=1,
activation='relu', learning_rate='adaptive',max_iter=5000
)
gcv = GridSearchCV(model_mlp,param_grid=para_dict ,cv = 5,n_jobs=-1)
gcv.fit(X_train, y_train)
mlp_score=gcv.score(X_test,y_test)
print('回归模型得分',mlp_score)
y_pred = gcv.predict(X_test)
# 可视化看看测试集拟合效果
plt.figure()
plt.plot([i for i in range(len(X_test))],y_pred,label='拟合曲线')
plt.plot([i for i in range(len(X_test))],y_test,label='真实曲线')
plt.title("测试集拟合效果")
plt.legend()
plt.show()
多层感知机好一点,但是效果还是不太好。当然我也试了BP(用了一个通宵,效果依然很差!!!到了一定时候梯度下降就无法降低损失,陷入局部最优解了)
从这个定价分布来看,其实没有任何明显的关系,数据太随机了所以没有很好的拟合效果也是情有可原,然后我用了svr去拟合,一番调参过后效果是最好的,所以我就用的svr去回归预测。
4.用svr给未完成的任务重新定价
unfinished=data[data['任务执行情况']==0]
unfinished.head()
X=unfinished[['主成分1','主成分2','主成分3','主成分4','主成分5','主成分6','主成分7','主成分8','主成分9','主成分10','主成分11']]
scaler=StandardScaler().fit(X)
X=scaler.transform(X)
Y=svr.predict(X)
unfinished['重新定价']=Y
unfinished.head()
5.用原价格和主成分去训练SVM分类模型
# 使用svm对所有数据训练分类模型
# 划分数据集
X=data[['任务标价','主成分1','主成分2','主成分3','主成分4','主成分5','主成分6','主成分7','主成分8','主成分9','主成分10','主成分11']]
Y=data['任务执行情况']
Y=np.array(Y).reshape(-1,1)
scaler=StandardScaler().fit(X)
X=scaler.transform(X)
X_train, X_test, y_train, y_test = train_test_split(X,Y, test_size=0.2, random_state=2)
print(X_train.shape,y_test.shape)
from sklearn.svm import SVC
from sklearn import metrics as sm
svm=SVC()
parameters=[{'kernel': ['linear','rbf','poly'],'C': [0.01,0.1,1,10],'gamma':[0.001,0.01,0.1,1,10],'degree':[2,3,4,5,6,7]}]
clf = GridSearchCV(svm,parameters,scoring='accuracy',cv=5,n_jobs=-1)
clf.fit(X_train, y_train)
svm=clf.best_estimator_
svm.fit(X_train,y_train)
y_pred=svm.predict(X_test)
matrix=sm.confusion_matrix(y_test,y_pred)
report=sm.classification_report(y_test,y_pred)
def plot_confusion_matrix(confusion_mat):
df_cm = pd.DataFrame(confusion_mat,index=[1,2],columns=[1,2])
ax = sns.heatmap(df_cm,annot=True,fmt='.20g')
ax.set_title('混淆矩阵')
ax.set_xlabel('预测标签')
ax.set_ylabel('真实标签')
plt.show()
plot_confusion_matrix(matrix)
print(report)
模型效果依然不是特别好,准确率和f1分数都不是特别高。期待着后期能有优化,但是现在的我只想早点做完。最近因为忙着写作业都快一周没有怎么看考研相关的了,老师也原谅一下我偷懒啦
6.用刚刚训练好的SVM对新的价格和特征做预测
# 对未执行任务中新的定价以及主成分用svm做预测
X=unfinished[['重新定价','主成分1','主成分2','主成分3','主成分4','主成分5','主成分6','主成分7','主成分8','主成分9','主成分10','主成分11']]
scaler=StandardScaler().fit(X)
X=scaler.transform(X)
y_pred=svm.predict(X)
unfinished['新的完成情况']=y_pred
unfinished.head()
7.模型评价
看看新的定价情况下,任务完成数会增加多少,另外新的定价比原始定价会增加多少金额
把表格中所有新的完成情况为1的统计,然后再把价格作差
new_finish_num=unfinished[unfinished['新的完成情况']==1]['新的完成情况'].sum()
increase_price=unfinished['重新定价'].sum()-unfinished['任务标价'].sum()
print("新增加的完成数:",new_finish_num)
print("新增加的价格:",increase_price)
增加的金额27.5小于50,任务完成数增加了89,达到了要求。
最后
最近真的太累了,我只想安安心心的复习考研,但是事情又太多,比赛、作业,太难了。所以这个作业其实做的很应付,我一般都比较喜欢追求完美的,但是后来慢慢发现事情太多了没办法把每件事都做到最好,还是要分重要的去做。
模型的误差问题
SVR拟合的R2只有0.58,SVM的准确率也只有0.82,所以虽然最后的结果满足了条件,但是并不能很好的说明问题。不过有一点,钱多人就愿意做事这个道理还是体现的很深刻的。至于优化的话,等我复习累了我会去想想怎么提高回归拟合程度。