过去4个月中每小时记录一次我的数据。我正在构建时间序列模型,到目前为止,我已经尝试了几种方法:Arima,LSTM,Prophet,但是它们对于我的任务来说可能会很慢,因为我必须在不同位置的数千个时间序列上运行模型。因此,我认为将其转换为监督问题并使用回归可能很有趣。
我从单变量时间序列及其时间索引中提取了4个特征,即:星期几,小时,日均值和时均值。因此,目前我正在使用这4个预测变量,但可能会提取更多(例如,一天的开始,中午等,如果您在此处还有其他建议,也非常欢迎它们:))
我已使用XGBoost进行回归,这是代码的一部分:
# XGB
import xgboost as xgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score
# Functions needed
def convert_dates(x):
x['date'] = pd.to_datetime(x['date'])
#x['month'] = x['date'].dt.month
#x['year'] = x['date'].dt.year
x['dayofweek'] = x['date'].dt.dayofweek
x['hour'] = x['date'].dt.hour
#x['week_no'] = pd.to_numeric(x['date'].index.strftime("%V"))
x.pop('date')
return(x)
def add_avg(x):
x['daily_avg']=x.groupby(['dayofweek'])['y'].transform('mean')
x['hourly_avg'] = x.groupby(['dayofweek','hour'])['y'].transform('mean')
#x['monthly_avg']=x.groupby(['month'])['y'].transform('mean')
#x['weekly_avg']=x.groupby(['week_no'])['y'].transform('mean')
return x
xgb_mape_r2_dict = {}
然后我运行一个for循环,在其中选择一个位置并为其建立模型。在这里,我将数据分为训练和测试部分。我知道上周我国的复活节假期可能会造成问题,因为那是罕见的事件,所以这就是为什么我以这种方式划分训练和测试数据。因此,我实际上将从年初到两周前的数据视为训练数据,并将其后第二周的数据视为测试数据。
for j in range(10,20):
data = df_all.loc[df_all['Cell_Id']==top_cells[j]]
data.drop(['Cell_Id', 'WDay'], axis = 1, inplace = True)
data['date'] = data.index
period = 168
data_train = data.iloc[:-2*period,:]
data_test = data.iloc[-2*period:-period,:]
data_train = convert_dates(data_train)
data_test = convert_dates(data_test)
data_train.columns = ['y', 'dayofweek', 'hour']
data_test.columns = ['y', 'dayofweek', 'hour']
data_train = add_avg(data_train)
daily_avg = data_train.groupby(['dayofweek'])['y'].mean().reset_index()
hourly_avg = data_train.groupby(['dayofweek', 'hour'])['y'].mean().reset_index()
现在,对于测试数据,我添加了过去的平均值,即过去的7个每日平均值和过去的168个小时平均值。实际上,这是运行时间最长的部分,我想提高其效率。
value_dict ={}
for k in range(168):
value_dict[tuple(hourly_avg.iloc[k])[:2]] = tuple(hourly_avg.iloc[k])[2]
data_test['daily_avg'] = 0
data_test['hourly_avg'] = 0
for i in range(len(data_test)):
data_test['daily_avg'][i] = daily_avg['y'][data_test['dayofweek'][i]]
data_test['hourly_avg'][i] = value_dict[(data_test['dayofweek'][i], data_test['hour'][i])]
对于for循环中的每个迭代,我当前的运行时间为30秒,这太慢了,因为我用很差的方法将平均值添加到测试数据中。如果有人能指出我该如何更快地实现这一点,我将不胜感激。
我还将添加其余代码,并进行其他一些观察:
x_train = data_train.drop('y',axis=1)
x_test = data_test.drop('y',axis=1)
y_train = data_train['y']
y_test = data_test['y']
def XGBmodel(x_train,x_test,y_train,y_test):
matrix_train = xgb.DMatrix(x_train,label=y_train)
matrix_test = xgb.DMatrix(x_test,label=y_test)
model=xgb.train(params={'objective':'reg:linear','eval_metric':'mae'}
,dtrain=matrix_train,num_boost_round=500,
early_stopping_rounds=20,evals=[(matrix_test,'test')],)
return model
model=XGBmodel(x_train,x_test,y_train,y_test)
#submission = pd.DataFrame(x_pred.pop('id'))
y_pred = model.predict(xgb.DMatrix(x_test), ntree_limit = model.best_ntree_limit)
#submission['sales']= y_pred
y_pred = pd.DataFrame(y_pred)
y_test = pd.DataFrame(y_test)
y_test.reset_index(inplace = True, drop = True)
compare_df = pd.concat([y_test, y_pred], axis = 1)
compare_df.columns = ['Real', 'Predicted']
compare_df.plot()
mape = (np.abs((y_test['y'] - y_pred[0])/y_test['y']).mean())*100
r2 = r2_score(y_test['y'], y_pred[0])
xgb_mape_r2_dict[top_cells[j]] = [mape,r2]
我已经使用R平方和MAPE来作为准确性度量,尽管我不认为MAPE可以再显示了,因为我已经将时间序列问题转换为回归问题。您对此主题有何想法?
非常感谢您的时间和考虑。非常感谢您的帮助。
更新:我已经设法通过使用熊猫的合并来解决此问题。我首先创建了两个数据框,其中包含来自训练数据的每日平均值和小时平均值,然后将这些ataframe与测试数据合并:
data_test = merge(data_test, daily_avg,['dayofweek'],'daily_avg')
data_test = merge(data_test, hourly_av['dayofweek','hour'],'hourly_avg')
data_test.columns = ['y', 'dayofweek', 'hour', 'daily_avg', 'hourly_avg']
我们将合并功能定义为:
def merge(x,y,col,col_name):
x =pd.merge(x, y, how='left', on=None, left_on=col, right_on=col,
left_index=False, right_index=False, sort=True,
copy=True, indicator=False,validate=None)
x=x.rename(columns={'sales':col_name})
return x
我现在可以在笔记本电脑上以每小时2000个位置的速度运行该模型,并获得不错的结果,但是我会尽力对其进行改进,同时保持快速。再次非常感谢您。