我自己编写了这个支持向量回归(SVR),它遵循日记中的一些公式(参见这里,或这里 (非英语))。日志和下面的代码使用的损失函数是平均绝对百分比误差(MAPE)。
我需要让它运行得更快,因为我将使用这个函数1600次进行评估。如果我使用此代码,它将运行几天,甚至一周运行一次。
我怎样才能让它跑得更快?我是Python的初学者(第一次用Python编写代码)。
我使用的股票市场数据示例:TLKM.CSV
您可以在这里看到代码:SVRpython.py或更低版本:
import csv
import pandas as pd
import numpy as np
import math
import matplotlib.pyplot as plt
import random as Rand
from pandas import DataFrame
from sklearn.model_selection import train_test_split
import pdb
import time
nstart=time.process_time()
# pdb.set_trace()
# import IPython as IP
data = pd.read_csv("TLKM.csv")
def Distancetrain(d3, d2, d1):
d=len(d3.index)
harray=[]
for i in range(d):
harray.clear()
for j in range(d):
harray.append(((d3.iloc[i]-d3.iloc[j])**2) + ((d2.iloc[i]-d2.iloc[j])**2) + ((d1.iloc[i]-d1.iloc[j])**2))
if i < 1:
distancedata=pd.DataFrame(harray)
else:
distancedata[i]=harray
print("distance train")
print(time.process_time()-nstart)
return distancedata
def Distancetest(d3train, d2train, d1train, d3test, d2test, d1test):
dtrain=len(d3train.index)
dtest=len(d3test.index)
harray=[]
for i in range(dtrain):
harray.clear()
for j in range(dtest):
harray.append(((d3test.iloc[j]-d3train.iloc[i])**2) + ((d2test.iloc[j]-d2train.iloc[i])**2) + ((d1test.iloc[j]-d1train.iloc[i])**2))
if i < 1:
distancedata=pd.DataFrame(harray)
else:
distancedata[i]=harray
print("distance test")
print(time.process_time()-nstart)
return distancedata
def Hessian(dfdistance, sigma, lamda):
d=len(dfdistance.index)
col=len(dfdistance.columns)
hes = np.array([], dtype=np.float64).reshape(0,col)
tampung = [[0] * col]
sig2= 2*(sigma**2)
lam2=lamda**2
for i in range(d):
for j in range(col):
tampung[0][j]=np.exp(-1*((dfdistance.iloc[i][j])/(sig2))) + (lam2)
hes=np.vstack([hes, tampung])
dfhessian=pd.DataFrame(hes)
print("hessian")
print(time.process_time()-nstart)
return dfhessian
def Seqlearn(y, dfhessian, gamma, eps, c, itermaxsvr):
d=len(dfhessian.index)
a = [[0] * d]
a_s = [[0] * d]
la = [[0] * d]
la_s = [[0] * d]
E = np.array([], dtype=np.float64).reshape(0,d)
Etemp = [[0] * d]
da_s = np.array([], dtype=np.float64).reshape(0,d)
da = np.array([], dtype=np.float64).reshape(0,d)
dat_s = [[0] * d]
dat = [[0] * d]
tempas = [[0] * d]
tempa = [[0] * d]
for i in range(itermaxsvr):
for j in range(d):
Rijhelp=0
for k in range(d):
Rijhelp = Rijhelp + ((a_s[i][k] - a[i][k])*(dfhessian.iloc[j][k]))
Etemp[0][j]= y.iloc[j] - Rijhelp
E=np.vstack([E, Etemp])
for l in range(d):
dat_s[0][l]=min(max(gamma*(E[i][l] - eps), -1*(a_s[i][l])), (c - a_s[i][l]))
dat[0][l]=min(max(gamma*(-(E[i][l]) - eps), -1*(a[i][l])), (c - a[i][l]))
tempas[0][l]= a_s[i][l] + dat_s[0][l]
tempa[0][l]= a[i][l] + dat[0][l]
da_s=np.vstack([da_s, dat_s])
da=np.vstack([da, dat])
a=np.vstack([a, tempa])
a_s=np.vstack([a_s, tempas])
la=tempa
la_s=tempas
# (|da| 0):
dataxm=np.vstack([dataxm, datax])
print("predict")
print(time.process_time()-nstart)
return dataxm
def Normalization(datain, closemax, closemin):
dataout=(datain - closemin)/(closemax - closemin)
return dataout
def SVRf(df, closemax, closemin, c, lamda, eps, sigma, gamma, itermaxsvr):
result = df.assign(Day_3 = Normalization(df.Day_3, closemax, closemin), Day_2=Normalization(df.Day_2, closemax, closemin), Day_1=Normalization(df.Day_1, closemax, closemin), Actual=Normalization(df.Actual, closemax, closemin))
X_train, X_test, y_train, y_test, d3_train, d3_test, d2_train, d2_test, d1_train, d1_test, date_train, date_test = train_test_split(result['Index'], result['Actual'], result['Day_3'], result['Day_2'], result['Day_1'], result['Date'], train_size=0.9, test_size=0.1, shuffle=False)
distancetrain=Distancetrain(d3_train, d2_train, d1_train)
mhessian=Hessian(distancetrain, sigma, lamda)
a, a_s = Seqlearn(y_train, mhessian, gamma, eps, c, itermaxsvr)
distancetest=Distancetest(d3_train, d2_train, d1_train, d3_test, d2_test, d1_test)
testhessian=Hessian(distancetest, sigma, lamda)
predict = Predictf(a, a_s, testhessian)
hasilpre=pd.DataFrame()
tgltest = date_test
tgltest.reset_index(drop=True, inplace=True)
hasilpre['Tanggal'] = tgltest
hasilpre['Close'] = predict
deresult = hasilpre.assign(Close=(hasilpre.Close * (closemax - closemin) + closemin))
n=len(y_test)
aktualtest = (y_test * (closemax - closemin)) + closemin
aktualtest.reset_index(inplace=True, drop=True)
dpredict = pd.Series(deresult['Close'], index=deresult.index)
hasil = aktualtest - dpredict
hasil1 = (hasil / aktualtest).abs()
suma = hasil1.sum()
mape = (1/n) * suma
print("MAPE")
print(mape)
fitness = 1/(1+mape)
print(fitness)
return fitness, mape, hasilpre
Closemax=data['Close'].max()
Closemin=data['Close'].min()
print(Closemax)
print(Closemin)
day3 = data['Close'][0:((-1)-2)]
day2 = data['Close'][1:((-1)-1)]
day2.index = day2.index - 1
day1 = data['Close'][2:((-1)-0)]
day1.index = day1.index - 2
dayact = data['Close'][3:]
dayact.index = dayact.index - 3
dateact = data['Tanggal'][3:]
dateact.index = dateact.index - 3
mydata = pd.DataFrame({'Index':data['Index'][0:((-1)-2)], 'Date':dateact, 'Day_3':day3, 'Day_2':day2, 'Day_1':day1, 'Actual':dayact})
print("data proses",time.process_time()-nstart)
Lamda=0.09
C=200
Eps=0.0013
Sigma=0.11
Gamma=0.004
Itermaxsvr=1000
SVRf(mydata, Closemax, Closemin, C, Lamda, Eps, Sigma, Gamma, Itermaxsvr)
nstop=time.process_time()
print(nstop-nstart)
发布于 2020-02-05 23:12:00
首先也是最重要的:去给自己买一个带有自动格式化程序的IDE,例如PyCharm、带有Python插件的代码 (仅举几个例子,关于代码审查的另一篇文章中有更长的列表)。这将帮助您建立一致的代码样式,这反过来又使您更容易阅读和检查代码。Python附带了一个“正式”Python代码样式指南 (又名PEP 8),这些工具极大地帮助编写了看起来专业的代码。需要特别注意的一些方面:
=
前后的空白,例如distancedata = pd.DataFrame(harray)
lower_case_with_underscore
名称,例如def distances_train(d3, d2, d1): ...
"""documentation"""
一旦您了解了这一点,我强烈建议您看看Jake的一些讨论:
还有一个强烈推荐的读取器,可以使用相同的人在Python:Python数据科学手册中进行数值计算。你要花些时间来解决这个问题,但我保证这是值得的。
我所链接的材料的核心是:循环在普通Python中是缓慢的,所以通常最好尽量避免它们。
我将演示使用Distancetrain
def距离序列(d3,d2,d1):d= len(d3.index) harray = [] in range(d):harray.clear()表示范围(D)中的j:harray.append(d3.iloc-d3.iloc)**2)+ ((d2.iloc-d2.iloc)**2) +((d1.iloc-d1.iloc)**2)远程数据= pd.DataFrame( harray ):distancedata =harray返回距离数据
使这个功能慢下来的东西:
for
循环那么,如何才能改善这一点呢?由于远程计算在各种机器学习应用中都是一项非常常见的任务,因此在枕骨的C45
模块中有很好的库支持。你已经在使用朗皮,熊猫和滑雪,所以有一个很大的机会,枕木也是可用的。
查看上面链接的模块文档,显示了两个非常方便的函数:pdist
和cdist
。pdist
基本上等同于Distancetrain
应该做的事情,当考虑对Distancetest
的改进时,cdist
将变得非常方便。
通过这个函数,Distancetrain
变得非常容易实现:
def as_column(series):
"""Reshapes a pandas series to a numpy column vector"""
return series.to_numpy(copy=False).reshape((-1, 1))
def distances_train(d3, d2, d1):
# pdist requires the input to have a shape of (n_samples, n_dimensions)
np_data = np.concatenate((as_column(d3), as_column(d2), as_column(d1)), axis=1)
# squareform is used to get the full distance matrix from the half triangle I talked about earlier
return pd.DataFrame(squareform(pdist(np_data, "sqeuclidean")))
所有这些重塑、连接和转换回数据文件基本上都是不必要的。我只保留它们,以便输出与原始代码兼容。您可以使用np.allclose(arr1, arr2)
亲自查看结果是否确实是相同的。
以前必须由Python解释器执行的循环现在在底层库实现中执行。数值Python库通常是用C编写的,因此(在大多数情况下)比普通Python代码编写循环要快得多。
非正式的时间安排产生了以下结果(平均超过10次):
original: 15.3467 s
new: 0.0031 s
差不多快了5000倍!
您可以以相同的方式重写代码的其他部分。只是需要一段时间才能习惯于从更大的数组和矩阵操作的角度来考虑这个问题。要达到这个目的,一种经过尝试和测试的方法是重写部分代码,同时保留旧代码以检查结果是否匹配。有时他们没有,但这不应该阻止你进一步调查它。通常情况下,重写的版本可能是正确的,因为没有复杂的循环等等,它更容易和简单。
也许还可以看看南巴,一种用于Python代码的即时编译器。这有时可以显著加快循环速度(例如,请参阅这里 )。numba并不完全支持您在Python或numpy中所能做的一切,因此实现可能需要一些调整才能正确地使用它。
当然,概要分析也是这一过程中的关键,并在评论中提到过。Python的内置cProfile
模块对此非常有用。timeit
还可用于可靠地测量较小代码段的执行时间。
https://codereview.stackexchange.com/questions/236646
复制相似问题