2019-11-04 09:35:19 qq_29440983 阅读数 294
  • 机器学习&深度学习系统实战!

    购买课程后,可扫码进入学习群,获取唐宇迪老师答疑 数学原理推导与案例实战紧密结合,由机器学习经典算法过度到深度学习的世界,结合深度学习两大主流框架Caffe与Tensorflow,选择经典项目实战人脸检测与验证码识别。原理推导,形象解读,案例实战缺一不可!具体课程内容涉及回归算法原理推导、决策树与随机森林、实战样本不均衡数据解决方案、支持向量机、Xgboost集成算法、神经网络基础、神经网络整体架构、卷积神经网络、深度学习框架--Tensorflow实战、案例实战--验证码识别、案例实战--人脸检测。 专属会员卡优惠链接:http://edu.csdn.net/lecturer/1079

    40478 人正在学习 去看看 唐宇迪

在2019年10月某个夜黑风高的夜晚,程序猿小甘在散步过程中,路过了一家“中国福利彩票站”时,看着陆续走出的彩民,突然也升起了一颗能中500W的心,然而作为一位只懂双色球中奖规则的垃圾彩民来说,买双色球也只能买机选,顿时觉得中奖希望渺茫(虽然渺茫但是还是去买了注机选双色球...),在排队购买过程中,听着那些经验丰富的彩民说着什么黄金分割选号、尾数分布选号、相减排除等等时,才发现原来买彩票还有这么多讲究。当时灵光一现,作为一名深度学习搬砖师,为什么不结合大数据和深度学习来预测双色球的结果呢?于是程序猿小甘准备结束CSDN的四年潜水,开始了他在CSDN的博主之旅....

项目工作环境:

  1. python3.5

  2. tensorflow-gpu1.9.0

  3. beautifulsoup

  4. windows10

  5. ....

环境配置都比较简单,网上也有非常多的教程,在这里我就不再进行赘述了

数据准备:

不论使用深度学习来解决预测、识别、分类等等问题,一份足够庞大的数据都是不可少的,而这次小甘准备通过爬虫的方式,从网上爬取往期双色球中奖号码来作为训练和测试数据。

通过某度搜索"双色球中奖结果",比较了500彩票网彩经网福彩网双色球官网http://kaijiang.zhcw.com/zhcw/html/ssq/list_1.html等等,发现http://kaijiang.zhcw.com/zhcw/html/ssq/list_1.html更利于爬取数据,于是果断的开始了爬虫的编写。

该网站的中奖结果结构如下:

我们只需要将每一期的开奖日期、期号、中奖号码,按照('2019-07-23','2019085', '01,04,14,18,24,29,04')这样的格式保存在txt文件中就行了。

  1. 对网页源代码进行分析,我们所需要的数据所在代码在如下图,主要需要<td align="center">和<em>标签中的内容
  2. 因为我们需要爬取出该网站尽可能多的数据,所以还需要中奖结果的总页数,如下图
  3. 使用Python编写爬虫代码,我们主要使用了beautifulsoup来完成数据爬取,主要代码片段如下。
#获取该网页的源代码
def getPage(url):
    try:
        user_agent = 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36'
        header = {'User-Agent': user_agent}
        request = urllib.request.Request(url,headers=header)
        response = urllib.request.urlopen(request)
        pageCode = response.read().decode('utf-8')
        return pageCode
    except Exception as e:
        print('Get Page Fail')
        print("An error has occurred:"+e)

#将双色球的信息写入txt文件
def writePage(date,dateNum,num):
    #日期的列表会比期号长1,因为最后加入了一组页数统计,所以不能以日期列表长度来写数据
    with open('./DCnumber.txt','a+') as f:
        for x in range(0,len(num)):
            f.write('('+date[x]+';'+dateNum[x]+';'+num[x]+')'+'\n')
            #保存格式为每行('2019-09-24';'2019112';'03,12,14,17,23,27,01')

#获取总页数
def getPageNum(url):
    try:
        pageCode = getPage(url)
        soup = BeautifulSoup(pageCode,'lxml')
        td_code = soup.find('td',colspan='7')       #获取表格中包含页数的列
        result = td_code.get_text().split(' ')      #将该列转换成列表,我们
        #result = ['\n', '共125', '页', '/2484', '条记录', '首页', '上一页', '下一页', '末页', '当前第', '2', '页']
        #用正则表达式从reslut[1]中提取出数字
        list_num = re.findall("[0-9]{1}",result[1])
        #将提取出来的数字转换成十进制的数值
        page_num = int(list_num[0]+list_num[1]+list_num[2])
        return page_num
    except Exception as e:
        print('Get Page Number Fail')
        print("An error has occurred:" + e)

#获取单页中的双色球中奖信息
def getDC(url):
    #循环读取每一页的信息
    for num in range(1,getPageNum(url)+1):
        print('begin get page:'+str(num))
        href = 'http://kaijiang.zhcw.com/zhcw/html/ssq/list_'+str(num)+'.html'
        page = BeautifulSoup(getPage(href),'lxml')
        em_list = page.find_all('em')   #获取该页面中的em内容,即中奖编号所在
        td_list = page.find_all('td',{'align':'center'})    #获取该页面中的开奖日期,期号等信息

        i = 1   #计数器,每七个号码为一组
        DCnum = ''      #存放一期中奖号码
        DCnum_list = []     #存放该页每期的中奖号码
        for em in em_list:
            emnum = em.get_text()
            if i == 7:
                DCnum = DCnum + emnum
                DCnum_list.append(DCnum)
                DCnum = ''          #重置一期的号码
                i = 1               #重置计数器
            else:
                DCnum = DCnum + emnum + ','
                i += 1

        DCdate = []         #存放开奖日期
        DCdateN = []        #存放期号
        t = 1              #计数器,每5个为一组,我们只需要每组的前两个td内容
        for td in td_list:
            td_text = td.get_text()
            if t == 1:
                DCdate.append(td_text)
                t += 1
            elif t == 2:
                DCdateN.append(td_text)
                t += 1
            elif t == 5:
                t = 1
            else:
                t += 1
        writePage(DCdate,DCdateN,DCnum_list)

到目前为止,训练数据和测试数据就准备完毕了,将在下一篇中介绍到重点内容,即基于Tensorflow的深度学习模型训练和数据预测。

终于完成了属于我的第一篇博文,所谓万事开头难,肯定会有很多不足的地方,希望大家能谅解...

2020-03-07 09:38:54 weixin_40359716 阅读数 35
  • 机器学习&深度学习系统实战!

    购买课程后,可扫码进入学习群,获取唐宇迪老师答疑 数学原理推导与案例实战紧密结合,由机器学习经典算法过度到深度学习的世界,结合深度学习两大主流框架Caffe与Tensorflow,选择经典项目实战人脸检测与验证码识别。原理推导,形象解读,案例实战缺一不可!具体课程内容涉及回归算法原理推导、决策树与随机森林、实战样本不均衡数据解决方案、支持向量机、Xgboost集成算法、神经网络基础、神经网络整体架构、卷积神经网络、深度学习框架--Tensorflow实战、案例实战--验证码识别、案例实战--人脸检测。 专属会员卡优惠链接:http://edu.csdn.net/lecturer/1079

    40478 人正在学习 去看看 唐宇迪

一、比赛说明:
评分标准

评分算法通过logarithmic loss(记为logloss)评估模型效果,logloss越小越好。
目标:预估用户人群在 规定时间内产生购买行为的概率 1买, 0不买
在这里插入图片描述
其中N 表示测试集样本数量,
yi 表示测试集中 第i个样本的真实标签,
pi 表示第 i个样本的预估转化率,
δ 为惩罚系数。
AB榜的划分方式和比例:
【1】评分采用AB榜形式。排行榜显示A榜成绩,竞赛结束后2小时切换成B榜单。B榜成绩以选定的两次提交或者默认的最后两次提交的最高分为准,最终比赛成绩以B榜单为准。

【2】此题目的AB榜数据采用 同时段数据 是随机划分,A榜为随机抽样测试集50%数据,B榜为其余50%的数据。

二、 数据集
https://pan.baidu.com/s/1cPX5jPCuOLDWkEGtCg6OcQ
提取码:uqb5
三、过程:

  • 赛题分析
  • 数据去操
  • 特征选择、构造:挑选有用的特征,生成一些间接的特征(https://zhuanlan.zhihu.com/p/32749489)
  • 模型选择
  • 结果评估
    四、特征处理
    我们总共构建了75个指标,其中包括52个基本指标,23个重要指标的变换,平方,对数

购买次数: customer_counts

省份: customer_province

城市: customer_city


首先对其中的异常值进行处理,包括用众数填充,平均数填充。
之后对数据中的噪声(特殊值)进行处理,删除,改为指定数值,进而缩小数据的范围。
之后对范围较大的数据,做离差标准化处理,映射到(0,1)区间内。

# 此处只是列举了特征选取的一部分
for idx, data in enumerate([train_last, train_all]):
        customer_all = pd.DataFrame(data[['customer_id']]).drop_duplicates(['customer_id']).dropna()
        data = data.sort_values(by=['customer_id', 'order_pay_time'])
        data['count'] = 1
        # 一、购买次数
        tmp = data.groupby(['customer_id'])['count'].agg({'customer_counts': 'count'}).reset_index()
        customer_all = customer_all.merge(tmp, on=['customer_id'], how='left')
        # 二、 省份 , last() 由迭代式获取其中的值, reset_index() 重置索引
        tmp = data.groupby(['customer_id'])['customer_province'].last().reset_index()
        customer_all = customer_all.merge(tmp, on=['customer_id'], how='left')
        # 三、城市
        tmp = data.groupby(['customer_id'])['customer_city'].last().reset_index()
        customer_all = customer_all.merge(tmp, on=['customer_id'], how='left')
        # 四、long_time : 在train 训练集中的 last - first 的时长, order_pay_date_last : 统计这个用户的订单最后一次购买时间
        last_time = data.groupby(['customer_id'], as_index=False)['order_pay_time'].agg(
            {'order_pay_date_last': 'max', 'order_pay_date_first': 'min'}).reset_index()
        tmp['long_time'] = pd.to_datetime(last_time['order_pay_date_last']) - pd.to_datetime(last_time['order_pay_date_first'])
        tmp['long_time'] = tmp['long_time'].dt.days + 1
        del tmp['customer_city']
        customer_all = customer_all.merge(tmp, on=['customer_id'], how='left')

解决倾斜特征

    # 解决倾斜特征
    numeric_dtypes = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
    numeric = []
    for i in last.columns:
        if last[i].dtype in numeric_dtypes:
            numeric.append(i)

为所有特征绘制箱型线图

    import seaborn as sns
    import matplotlib.pyplot as plt
    sns.set_style('white')
    f, ax = plt.subplots(figsize=(8, 7))
    ax.set_xscale('log')
    ax = sns.boxplot(data=last[numeric], orient='h', palette='Set1')
    ax.xaxis.grid(False)
    ax.set(ylabel='Feature names')
    ax.set(xlabel='Numeric values')
    ax.set(title='Numeric Distribution of Features')
    sns.despine(trim=True, left=True)

对数据的偏移进行修正,用scipy函数boxcox1p来计算Box-Cox转换,目标是使数据规范化

  # 寻找偏弱的特征
    from scipy.stats import skew, norm
 
    skew_features = last[numeric].apply(lambda x: skew(x)).sort_values(ascending=False)
    high_skew = skew_features[skew_features > 0.5]
    skew_index = high_skew.index
    skewness = pd.DataFrame({'Skew': high_skew})
    skew_features.head(10)
 
    # 用scipy函数boxcox1p来计算Box-Cox转换。我们的目标是找到一个简单的转换方式使数据规范化。
    from scipy.special import boxcox1p
    from scipy.stats import boxcox_normmax
 
    for i in skew_index:
        last[i] = boxcox1p(last[i], boxcox_normmax(last[i] + 1))
 
    # 处理所有的 skewed values
    sns.set_style('white')
    f, ax = plt.subplots(figsize=(8, 7))
    ax.set_xscale('log')
    ax = sns.boxplot(data=last[skew_index], orient='h', palette='Set1')
    ax.xaxis.grid(False)
    ax.set(ylabel='Feature names')
    ax.set(xlabel='Numeric values')

构造 logs 特征, squares 特征

    def logs(res, ls):
        m = res.shape[1]
        for l in ls:
            res = res.assign(newcol=pd.Series(np.log(1.01 + res[l])).values)
            res.columns.values[m] = l + '_log'
            m += 1
        return res
 
    def squares(res, ls):
        m = res.shape[1]
        for l in ls:
            res = res.assign(newcol=pd.Series(res[l] * res[l]).values)
            res.columns.values[m] = l + '_sq'
            m += 1
        return res

五、模型
自定义loss函数,实现线下、线上loss值偏差不大

# 由 loss 值计算score
def re_loglossv(labels,preds):
    deta = 3.45
    y_true = labels   # you can try this eval metric for fun
    y_pred = preds
    p = np.clip(y_pred, 1e-10, 1-1e-10)
    loss = -1/len(y_true) * np.sum(y_true * np.log(p) * deta + (1 - y_true) * np.log(1-p))
    return 're_logloss',loss,False

XGB模型参数设置:

    import xgboost as xgb
    # xgb 模型
    from sklearn.model_selection import KFold, RepeatedKFold, StratifiedKFold
    folds = StratifiedKFold(n_splits=5, shuffle=True, random_state=2019)
    # xgb模型参数设置
    xgb_params = {"booster": 'gbtree',
                  'eta': 0.005,
                  'max_depth': 5,
                  'subsample': 0.7,
                  'colsample_bytree': 0.8,
                  'objective': 'binary:logistic',
                  'eval_metric': 'logloss',
                  'silent': True,
                  'nthread': 8,
                  'scale_pos_weight': 2.5   # 处理正负样本不均衡
                  }
 
# -----------------------------------------------------------------------------------------------------------
 
    oof_xgb = np.zeros(len(X_train))
    predictions_xgb = np.zeros(len(X_valid))
    watchlist = [(xgb.DMatrix(X_train.as_matrix(), y_train.as_matrix()), 'train'),
                 (xgb.DMatrix(X_valid.as_matrix(), y_valid.as_matrix()), 'valid_data')]
    clf = xgb.train(dtrain=xgb.DMatrix(np.array(X_train), np.array(y_train)), num_boost_round=500, evals=watchlist,
                    early_stopping_rounds=200,
                    verbose_eval=100, params=xgb_params, feval=myFeval)
    oof_xgb = clf.predict(xgb.DMatrix(X_valid.as_matrix()), ntree_limit=clf.best_ntree_limit)
    pred_xgb = clf.predict(xgb.DMatrix(X_all.as_matrix()), ntree_limit=clf.best_ntree_limit)
    res = all_data[['customer_id']]
    res['result'] = pred_xgb
    # 保存 xgb模型
    # clf.save_model('./xgb.model_true_false')
    # load model
    # bst2 = xgb.Booster(model_file='xgb.model1')

对于XGB参数的调整
五折交叉验证:

  # 五折交叉验证
    for fold_, (trn_idx, val_idx) in enumerate(folds.split(train_x, train_y)):
        print("fold n°{}".format(fold_ + 1))
        trn_data = xgb.DMatrix(train_x[trn_idx], train_y[trn_idx])
        val_data = xgb.DMatrix(train_x[val_idx], train_y[val_idx])
        watchlist = [( trn_data, 'train'), (val_data, 'valid_data')]
        clf = xgb.train(dtrain=trn_data, num_boost_round=300, evals=watchlist, early_stopping_rounds=200,
                        verbose_eval=100, params=xgb_params, feval=myFeval)
        oof_xgb[val_idx] = clf.predict(xgb.DMatrix(train_x[val_idx]), ntree_limit=clf.best_ntree_limit)
        pred_xgb += clf.predict(xgb.DMatrix(X_all.as_matrix()), ntree_limit=clf.best_ntree_limit) / folds.n_splits
2020-04-01 13:09:20 weixin_43341045 阅读数 56
  • 机器学习&深度学习系统实战!

    购买课程后,可扫码进入学习群,获取唐宇迪老师答疑 数学原理推导与案例实战紧密结合,由机器学习经典算法过度到深度学习的世界,结合深度学习两大主流框架Caffe与Tensorflow,选择经典项目实战人脸检测与验证码识别。原理推导,形象解读,案例实战缺一不可!具体课程内容涉及回归算法原理推导、决策树与随机森林、实战样本不均衡数据解决方案、支持向量机、Xgboost集成算法、神经网络基础、神经网络整体架构、卷积神经网络、深度学习框架--Tensorflow实战、案例实战--验证码识别、案例实战--人脸检测。 专属会员卡优惠链接:http://edu.csdn.net/lecturer/1079

    40478 人正在学习 去看看 唐宇迪

前言

     去年大二上学期的时候,突然想尝试一下神经网络与深度学习的学习。毕竟博主是想以后做计算机视觉的,于是找我的导师闻了一下相关的学习方法,于是导师给了我一个预测判断牧场动物行为的项目。说实话,一开始心里还是挺没谱的,毕竟我还啥都不会啊ToT。不过人都不是从0到1的质变提升吗?所以我自己就买了一堆的书。在这里我是比较推荐

  1. ‘中国水利水电出版社’刘瑜先生的《Python编程》
  2. ‘中国水利水电出版社’蒋子阳先生的《TensorFlow深度学习算法原理与编程实战》
  3. ‘人民邮电出版社’斋藤康毅先生的《深度学习入门》
  4. ‘人民邮电出版社’塔里克·拉希德先生的《Python神经网络编程》
  5. ‘人民邮电出版社’IAN GOODFELLOW,YOSHUA BENGIO,AARON COURVILLE三位联合著写的《DEEP LEARNING》

     关于视频课程的话,我推荐去B站的莫烦Python,吴恩达先生的视频,以及3Blue1Brown等等。

壹.关于各种库的安装

     其实在我很多博客里面都有说过,如果还是不会安装库的同学请自行BaiDu或者阅读我之前的python博客。

import numpy as np#numpy做矩阵运算十分方便
import math#math函数用来设置一些激活函数
import random#需要随机数来做初始权重
import string
import matplotlib as mpl#如果你需要作图就用上
import matplotlib.pyplot as plt
import sys#需要保存最后的合理权重
import xlrd#因为我的数据集是从excel里面读出来的
from sklearn import preprocessing#需要对数据集做高斯分布或归一化的可以用这个

读取数据

     我这里是用的来自牧场方面给的Excel里面的各项数据集,如果是用MNIST或者其他来源的数据集的朋友可以跳过该步骤。差不多是一个三维的数据,我每次从两种行为里面取500组数据放入数组,并且给他们贴上0或1的标签【【【954】,【4652】,【-456】】【1】】差不多就是这种,前面是三维列表,后面是贴上的标签。

def read_excel():
    # 打开Excel
    workbook = xlrd.open_workbook('all.xls')
    # 进入sheet
    eating = workbook.sheet_by_index(0)
    sleeping=workbook.sheet_by_index(1)
    # 获取行数和列叔
    Srows_num=sleeping.nrows
    Scols_num=sleeping.ncols
    ListSleep=[]
    
    Erows_num = eating.nrows
    Ecols_num = eating.ncols
    ListEat=[]
    ListEatT=[]
    ListSleepT=[]
    ListT=[]
    i = 1
    while i <= 500:
        if Erows_num > 10 or Srows_num>10:
            # 生成随机数
            random_numE = random.randint(1, Erows_num - 1)
            E_X = eating.row(random_numE)[1].value
            E_Y = eating.row(random_numE)[3].value
            E_Z = eating.row(random_numE)[5].value
            ListEat.append([[int(E_X),int(E_Y),int(E_Z)],[1]])
            random_numS = random.randint(1, Srows_num - 1)
            S_X = sleeping.row(random_numS)[1].value
            S_Y = sleeping.row(random_numS)[3].value
            S_Z = sleeping.row(random_numS)[5].value
            ListSleep.append([[int(S_X),int(S_Y),int(S_Z)],[0]])
            i = i + 1
        else:
            print("数据不足,请添加")
            break
    List=ListEat+ListSleep
    
    print(List)
read_excel()

贰.激活函数

      这里是最重要的一步,一个好的适用的激活函数决定你这个网络的质量。

      1sigmoid函数

       sigmoid函数曲线如下:

         sigmoid激活函数,符合实际,当输入值很小时,输出接近于0;当输入值很大时,输出值接近于1。但sigmoid激活函数有较  大的缺点,是主要有两点:

(1)容易引起梯度消失。当输入值很小或很大时,梯度趋向于0,相当于函数曲线左右两端函数导数趋向于0。

(2)非零中心化,会影响梯度下降的动态性。

def sigmoid(x):
    '''
    定义sigmoid函数
    '''
    return 1.0/(1.0+np.exp(-x))
def derived_sigmoid(x):
    '''
    定义sigmoid导函数
    '''
    return sigmoid(x)*(1-sigmoid(x))

     2、tanh函数

     tanh函数曲线如下:

     与sigmoid相比,输出至的范围变成了0中心化[-1, 1]。但梯度消失现象依然存在。

def tanh(x):
    '''
    定义tanh函数
    '''
    return (np.exp(x)-np.exp(-x))/(np.exp(x)+np.exp(-x))
def derived_tanh(x):
    '''
    定义tanh导函数
    '''
    return 1-tanh(x)*tanh(x)

     3、Relu函数

     Relu修正线性单元是有许多优点,是目前神经网络中使用最多的激活函数。

     函数曲线如下:

优点:(1)不会出现梯度消失,收敛速度快;

          (2)前向计算量小,只需要计算max(0, x),不像sigmoid中有指数计算;

          (3)反向传播计算快,导数计算简单,无需指数、出发计算;

          (4)有些神经元的值为0,使网络具有saprse性质,可减小过拟合。

缺点:(1)比较脆弱,在训练时容易“死亡”,反向传播中如果一个参数为0,后面的参数就会不更新。使用合适的学习率会减弱这种情况。

def relu(x):
    '''relu函数'''
    return np.where(x<0,0,x)
 
def derivedrelu(x):
    '''relu的导函数'''
    return np.where(x<0,0,1)

     4、Leak Relu函数

     Leak Relu是对Relu缺点的改进,当输入值小于0时,输出值为αx,其中α是一个很小的常数。这样在反向传播中就不容易出现“die”的情况。

def leakyrelu(x,a=0.01):
    '''
    定义leakyrelu函数
    leakyrelu激活函数是relu的衍变版本,主要就是为了解决relu输出为0的问题
    '''
    return np.where(x<0,a*x,x)
 
def derived_leakyrelu(x,a=0.01):
    '''
    定义leakyrelu导函数
    '''
    return np.where(x<0,a,1)
 
 

     4、elu函数

 # 定义elu函数elu和relu的区别在负区间,relu输出为0,而elu输出会逐渐接近-α,更具鲁棒性。
def elu(x,a=0.01):
 #elu激活函数另一优点是它将输出值的均值控制为0(这一点确实和BN很像,BN将分布控制到均值为0,标准差为1)
    return np.where(x<0,a*(np.exp(x)-1),x)
 
def derived_elu(x,a=0.01):
    '''
    定义elu导函数
    '''
    return np.where(x<0,a*np.exp(x),1)

 除此之外还有很多派生的激活函数,请各位自己发掘了。

叁.数据的归一化处理

  输入输出数据的预处理:尺度变换。尺度变化也称为归一化或者标准化,是指变换处理将网络的输入、输出数据限制在[0,1]或者[-1,1]等区间内。进行变换的原因有三点:

 1).网络的各个输入数据常常具有不同的物理意义和不同的量纲。尺度变换使所有分量都在一个区间内变化,从而使网络训练一开始就给各输入分量以同等重要的地位;

 2).BP神经网络神经元均采用sigmoid函数,变换后可防止因净输入的绝对值过大而使神经元输出饱和,继而使权值调整进入误差曲面的平坦区;

 3).sigmoid函数输出在区间[0,1]或者是tanh函数[-1,1]内,如果不对期望输出数据进行变换处理,势必使数值大的分量绝对误差大,数值小的分量绝对误差小,总之数据最好要归一化。

2、(0,1)标准化:

  这是最简单也是最容易想到的方法,通过遍历feature vector里的每一个数据,将Max和Min的记录下来,并通过Max-Min作为基数(即Min=0,Max=1)进行数据的归一化处理:

                     

Python实现:

def MaxMin(x,Max,Min):
    x = (x - Min) / (Max - Min);
    return x

2、Z-score标准化:

这种方法给予原始数据的均值(mean)和标准差(standard deviation)进行数据的标准化。经过处理的数据符合标准正态分布,即均值为0,标准差为1,这里的关键在于复合标准正态分布:

 

                     

Python实现:

def Z_Score(x,mu,sigma):
    x = (x - mu) / sigma;
    return x

3、均值归一化

两种方式,以max为分母的归一化方法和以max-min为分母的归一化方法

 

def average():
    # 均值
    average = float(sum(data))/len(data)
 
    # 均值归一化方法
    data2_1 = [(x - average )/max(data) for x in data]
    data2_2 = [(x - average )/(max(data) - min(data)) for x in data]

肆.误差函数/损失函数

     一、均方误差Mean Squared Error

yk​是NN的输出
tk​是标签,只有正确解的标签为1,其他均为0.   k是数据维数
所以,均方误差计算NN的输出和正确标签数据的各个元素的差值的平方,再求总和。

def get_standard_deviation(records):
    """
    标准差 == 均方差 反映一个数据集的离散程度
    """
    variance = get_variance(records)
    return math.sqrt(variance)

     二、平均值average

def get_average(records):
    """
    平均值
    """
    return sum(records) / len(records)

    三、交叉熵误差Cross Entropy Error

单个训练数据的交叉熵误差只计算正确解标签的输出的自然对数。

yk​是NN的输出tk​标签,只有正确解的标签为1,其他均为0,k是数据维数

所以,当NN输出的正确解的概率y为1时,交叉熵损失为0;随着正确解的概率y向0减小,交叉熵损失减小(向负值减小,实际上损失值是在增大)

def cross_entropy(a, y):
    return np.sum(np.nan_to_num(-y*np.log(a)-(1-y)*np.log(1-a)))
 
# tensorflow version
loss = tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y), reduction_indices=[1]))
 
# numpy version
loss = np.mean(-np.sum(y_*np.log(y), axis=1))

 

伍.构建神经网络

   这上面的图只是一个示例,我最后的输出只有一个输出点,通过判断接近0或者1来判断行为的,多分类问题建议最后用softmax。这里的初始权值我有必要先说一下,最好设置为2的倍数,特别是要GPU加速的同学。
 

# 构造三层BP网络架构
class BPNN:
    def __init__(self, num_in, num_hidden, num_out):
        # 输入层,隐藏层,输出层的节点数
        self.num_in = num_in + 1  # 增加一个偏置结点
        self.num_hidden = num_hidden + 1  # 增加一个偏置结点
        self.num_out = num_out
        # 激活神经网络的所有节点(向量)
        self.active_in = [1.0] * self.num_in
        self.active_hidden = [1.0] * self.num_hidden
        self.active_out = [1.0] * self.num_out
        # 创建权重矩阵
        self.wight_in = makematrix(self.num_in, self.num_hidden)
        self.wight_out = makematrix(self.num_hidden, self.num_out)
        # 对权值矩阵赋初值

        for i in range(self.num_in):
            for j in range(self.num_hidden):
                self.wight_in[i][j] = random_number(-2.4, 2.4)
        for i in range(self.num_hidden):
            for j in range(self.num_out):
                self.wight_out[i][j] = random_number(-0.2, 0.2)
        # 最后建立动量因子(矩阵)
        self.ci = makematrix(self.num_in, self.num_hidden)
        self.co = makematrix(self.num_hidden, self.num_out)

     正向传播,这里我用了sigmoid作为初始数据集的归一化,因为我这里的数据最大和最小差的太多1000和3这种差距,像这种数据之间有太大的差异一定要归一化。tanh作为隐含层的激活函数,把隐含层的数据都统一在[-1,1]之间。最后用sigmoid输出判断这个数据靠近1还是靠近0。

   def update(self, inputs):
        print(len(inputs))
        if len(inputs) != self.num_in - 1:
            raise ValueError('输入层节点数有误')
            # 数据输入输入层
        for i in range(self.num_in - 1):
            self.active_in[i] = sigmoid(inputs[i])  #在输入层进行数据处理归一化

            self.active_in[i] = inputs[i]  # active_in[]是输入数据的矩阵
            # 数据在隐藏层的处理
        for i in range(self.num_hidden - 1):
            sum = 0.0
            for j in range(self.num_in):
                sum = sum + self.active_in[i] * self.wight_in[j][i]

            self.active_hidden[i] = tanh(sum)  # active_hidden[]是处理完输入数据之后存储,作为输出层的输入数据

            # 数据在输出层的处理
        for i in range(self.num_out):
            sum = 0.0
            print(self.wight_out)
            for j in range(self.num_hidden):

                sum = sum + self.active_hidden[j] * self.wight_out[j][i]
            self.active_out[i] = sigmoid(sum)  # 与上同理
        return self.active_out[:]
 

     反向传播

# 误差反向传播
    def errorback(self, targets, lr, m):  # lr是学习率, m是动量因子
        if len(targets) != self.num_out:
            raise ValueError('与输出层节点数不符!')
            # 首先计算输出层的误差
        out_deltas = [0.0] * self.num_out
        for i in range(self.num_out):
            error = targets[i] - self.active_out[i]
            out_deltas[i] = derived_sigmoid(self.active_out[i]) * error

            # 然后计算隐藏层误差
        hidden_deltas = [0.0] * self.num_hidden
        for i in range(self.num_hidden):
            error = 0.0
            for j in range(self.num_out):
                error = error + out_deltas[j] * self.wight_out[i][j]
            hidden_deltas[i] = derived_tanh(self.active_hidden[i]) * error

            # 首先更新输出层权值
        for i in range(self.num_hidden):
            for j in range(self.num_out):
                change = out_deltas[j] * self.active_hidden[i]
                self.wight_out[i][j] = self.wight_out[i][j] + lr * change + m * self.co[i][j]
                self.co[i][j] = change
            # 然后更新输入层权值
        for i in range(self.num_in):
            for j in range(self.num_hidden):
                change = hidden_deltas[j] * self.active_in[i]
                self.wight_in[i][j] = self.wight_in[i][j] + lr * change + m * self.ci[i][j]
                self.ci[i][j] = change
            # 计算总误差
        error = 0.0
        for i in range(len(targets)):
            error = error + 0.5 * (targets[i] - self.active_out[i]) ** 2

        return error

训练时j[0]为输入的三维列表,j[1]为每个列表的标签,lr为学习率,因为随着梯度的下降,学习率最好也随着缩小,就像一个人学习,一开始要学得多,最后要学得精。

 

BP算法的改进可以使用动量法m
动量法是在标准BP算法的权值更新阶段引入动量因子α(0<α<1),使权值修正具有一定惯性,也就是说误差能基本不变化其返回的信号对权值调整很小但是总误差能又大于训练结果设定的总误差能条件。这个时候加入一个动量因子有助于其反馈的误差信号使神经元的权值重新振荡起来。在原有的权值调整公式中,加入了动量因子以及上一次的权值改变量。加入的动量项表示本次权值的更新方向和幅度,不但与本次计算所得的梯度有关,还与上一次更新的方向和幅度有关。动量项反映了以前积累的调整经验,对于t时刻的调整起到了阻尼作用。当误差曲面出现骤然起伏时,可减小震荡趋势,提高训练速度。

 

  def train(self, pattern, itera=200000, lr=0.1, a=0.5):
        for i in range(itera):
            error = 0.0
            for j in pattern:
                input = j[0]
                targ = j[1]
                self.update(input)
                error = error + self.errorback(targ, lr, m)
            if i % 200 == 0:
                lr*=0.99
                print('误差 %-.5f' % error)
 记录下最后的权重保存在txt文档中
    def weights(self):
        f = open("getwights.txt", "w")
        weightin = []
        weightout = []
        print("输入层权重")
        for i in range(self.num_in):
            print(self.wight_in[i])
            weightin.append(self.wight_in[i])

        print("输入矩阵", weightin)
        print("输出层权重")
        for i in range(self.num_hidden):
            print(self.wight_out[i])
            weightout.append(self.wight_out[i])

        print("输出矩阵", weightout)
        f.write(str(weightin))
        f.write("\n")
        f.write(str(weightout))
        f.close()

然后创建神经网络,如果你不是3X3X1类型,也可以自己修改,然后在class里面也修改一下节点个数一样可以使用

def BP():
# 创建神经网络,3个输入节点,3  个隐藏层节点,1个输出层节点
    n = BPNN(3, 3, 1)
    # 训练神经网络
    n.train(List)
    # 保存权重值
    n.weights()
if __name__ == '__main__':
    BP()

既然保存了 我们训练后的权重,最后当然是使用了。其实和之前是一样的,就是初始权重不再是随机数而是我们之前保存的,然后只有正向传播。
 

class BPNN:
    def __init__(self, num_in, num_hidden, num_out):
        # 输入层,隐藏层,输出层的节点数
        self.num_in = num_in + 1  # 增加一个偏置结点
        self.num_hidden = num_hidden + 1  # 增加一个偏置结点
        self.num_out = num_out
        # 激活神经网络的所有节点(向量)
        self.active_in = [1.0] * self.num_in
        self.active_hidden = [1.0] * self.num_hidden
        self.active_out = [1.0] * self.num_out
        # 创建权重矩阵
        self.wight_in = makematrix(self.num_in, self.num_hidden)
        self.wight_out = makematrix(self.num_hidden, self.num_out)
        # 对权值矩阵赋初值
        f = open("getwights.txt", "r")
        a = f.readline()
        b = f.readline()
        listone = eval(a)
        listtwo = eval(b)
        f.close()
        for i in range(len(listone)):
            for j in range(len(listone[i])):
                self.wight_in[i][j] = listone[i][j]
        for i in range(len(listtwo)):
            for j in range(len(listtwo[i])):
                self.wight_out[i][j] = listtwo[i][j]

        self.co = makematrix(self.num_hidden, self.num_out)
        # 信号正向传播

    def update(self, inputs):
        if len(inputs) != self.num_in - 1:
            raise ValueError('与输入层节点数不符')
        # 数据输入输入层
        for i in range(self.num_in - 1):
            # self.active_in[i] = sigmoid(inputs[i])  #或者先在输入层进行数据处理
            self.active_in[i] = inputs[i]  # active_in[]是输入数据的矩阵
        # 数据在隐藏层的处理
        for i in range(self.num_hidden - 1):
            sum = 0.0
            for j in range(self.num_in):
                sum = sum + self.active_in[i] * self.wight_in[j][i]
            self.active_hidden[i] = tanh(sum)  # active_hidden[]是处理完输入数据之后存储,作为输出层的输入数据
        # 数据在输出层的处理
        for i in range(self.num_out):
            sum = 0.0
            for j in range(self.num_hidden):
                sum = sum + self.active_hidden[j] * self.wight_out[j][i]
            self.active_out[i] = sigmoid(sum)  # 与上同理
        return self.active_out[:]
    # 测试
    def test(self, patterns):
        distingish=[]
        List_update=[]
        num=0
        sum=0
        for i in patterns:
            List_update.append(self.update(i[0]))
        sum=np.sum(List_update,axis=0)
        average=sum/(len(patterns))
        #print(average)
        for i in patterns:
            num += 1
            if (num <= testnums and self.update(i[0]) > average):
                distingish.append(True)
            if (num > testnums and self.update(i[0]) < average):
                distingish.append(True)
            print(i[0], '->', self.update(i[0]))
        print("正确率", len(distingish) / num)


# 实例
def BP():

    # 创建神经网络,3个输入节点,3个隐藏层节点,1个输出层节点
    n = BPNN(3, 3, 1)
    # 测试神经网络
    n.test(ListT)
if __name__ == '__main__':
    BP()

 后序

我写过一片关于Pyecharts的文章,是关于数据可视化,有兴趣的朋友可以去看看

https://blog.csdn.net/weixin_43341045/article/details/104137445

关于这个数据的来源啊,可以很多种,我这里就介绍下爬虫。爬虫也有很多种库,写过一篇关于Selenium的爬虫https://blog.csdn.net/weixin_43341045/article/details/104014416

还有一个9行代码爬取B站专栏图片(BeautifulSoup4)

https://blog.csdn.net/weixin_43341045/article/details/104411456

     鄙人仅为一名普普通通大二学生,才学浅出,来此各地高人聚集处书写浅见,还望各位前辈高人多多指点海涵。我们诚邀各地有志之士加入我们的代码学习群交流:871352155(无论你会C/C++还是Java,Python还是PHP......有兴趣我们都欢迎你的加入,不过还请各位认真填写加群信息。群内目前多为大学生,打广告的先生女士就请不要步足了。我们希望有远见卓识的前辈能为即将步入社会的初犊提出建议指引方向。)

 


 

 

 

2020-03-08 16:03:47 qq_24601199 阅读数 43
  • 机器学习&深度学习系统实战!

    购买课程后,可扫码进入学习群,获取唐宇迪老师答疑 数学原理推导与案例实战紧密结合,由机器学习经典算法过度到深度学习的世界,结合深度学习两大主流框架Caffe与Tensorflow,选择经典项目实战人脸检测与验证码识别。原理推导,形象解读,案例实战缺一不可!具体课程内容涉及回归算法原理推导、决策树与随机森林、实战样本不均衡数据解决方案、支持向量机、Xgboost集成算法、神经网络基础、神经网络整体架构、卷积神经网络、深度学习框架--Tensorflow实战、案例实战--验证码识别、案例实战--人脸检测。 专属会员卡优惠链接:http://edu.csdn.net/lecturer/1079

    40478 人正在学习 去看看 唐宇迪

       去年的今天,我就开始有个小小的念头,拥有一个属于自己的博客,其实早在2017年底我就在阿里云购买了属于我自己的第一台服务器,那时的我不知天高地厚,扬言要做一个股票预测系统,并以此为自己的毕业设计,并且还说要把这个系统变成我博客的一个模块(现在想想,那时候真是初出牛犊不怕虎啊,啥都不会,还痴心妄想在短时间内搞定深度学习)。后来的结果是,勉强在老师的帮助下完成了(本科毕设你懂的),能走通流程,换句话就是说能跑得起来,能看得到结果,至于结果的准确性嘛,看看就好,不必在意。

       毕业后,准确说工作后三四个月后,开始和老友商量着搞一个系统,先以博客的形式出现,至于系统里面的东西,暂时保密(虽然说八字还没一撇,但总归是策划了,花了心血,以后有时间一定要搞出来,各位看官老爷小小期待一下吧~)。到后来各种各样的事情,我们都没足够的时间,于是乎一直拖(我自己懒还是主要原因),拖到了现在还没正式开始码代码。

       一转眼,时间来到了2020年,00后都开始自称老阿姨的年代了,不得不感慨一下,光阴似箭,日月如梭啊。这次下定了决心要弄出来这个博客,于是乎在小破站上找了给150+集的某教育集团的视频,开始了看视频之旅,当然也在各大知识的海洋中大概了解明白了Django的运行流程,自己也跑通了一遍,目前还在加前端模板整合过程中,我会不间断产出搭建过程的博客。

       这里我用到的环境如下:

       Django 1.11.7 

       Python 3.6.4

       MySQL 5.6.27

       PyCharm 2019.3

       阿里云服务器(1核 2G)

        我的这个项目准备用Django 1.11.7,这里我之所以不用2.2版本,是因为它还刚刚出来,肯定有各种各样的问题,敢说这种肯定的话,是因为我尝试过了,有个目前还没有修复的Bug,引用pymysql模块有问题,网上的解决办法就是降级到2.1.8版本,那我为何不用1.11.x这种LTS版本的呢?至于为什么不用1.8.x版本,你可能会说它也是LTS哇,在我的理念里有这么一句话,用新不用旧,还得用稳定,网上文档多的东西。综上所述,1.11.x版本就是最合适我的啦~(附Django版本发行周期图)

       说完Django版本的选择,接下来谈谈我为什么选择Python3.6.x吧,其实这也算是有点原因吧,你要知道一个事,Django不同版本对应的可以兼容的Python版本竟然是有要求的,具体对应情况如下,2.7当然是不太建议的了,毕竟从2020年也就是今年开始不再被支持了,其余的版本就看个人喜好咯,至于3.8版本,比较新,选择还请慎重。

 

2018-11-13 14:13:00 weixin_30787531 阅读数 10
  • 机器学习&深度学习系统实战!

    购买课程后,可扫码进入学习群,获取唐宇迪老师答疑 数学原理推导与案例实战紧密结合,由机器学习经典算法过度到深度学习的世界,结合深度学习两大主流框架Caffe与Tensorflow,选择经典项目实战人脸检测与验证码识别。原理推导,形象解读,案例实战缺一不可!具体课程内容涉及回归算法原理推导、决策树与随机森林、实战样本不均衡数据解决方案、支持向量机、Xgboost集成算法、神经网络基础、神经网络整体架构、卷积神经网络、深度学习框架--Tensorflow实战、案例实战--验证码识别、案例实战--人脸检测。 专属会员卡优惠链接:http://edu.csdn.net/lecturer/1079

    40478 人正在学习 去看看 唐宇迪

英伟达昨天一边发布“全球最大的GPU”,一边经历股价跳水20多美元,到今天发稿时间也没恢复过来。无数同学在后台问文摘菌,要不要抄一波底嘞?

今天用深度学习的序列模型预测股价已经取得了不错的效果,尤其是在对冲基金中。股价数据是典型的时间序列数据。

什么是序列数据呢?语音、文字等这些前后关联、存在内有顺序的数据都可以被视为序列数据。

将序列模型应用于语音和文字,深度学习在语音识别、阅读理解、机器翻译等任务上取得了惊人的成就。

具体怎么操作?效果又如何呢?来看文摘菌今天带来的这篇深度学习炒股指南。

对冲基金是深度学习应用中具有吸引力的领域之一,也是投资基金的一种形式。不少金融组织从投资者那里筹集资金后对其进行管理,并通过分析时间序列数据来做出一些预测。在深度学习中,有一种适用于时间序列分析的架构是:递归神经网络(RNNs),更具体地说,是一种特殊类型的递归神经网络:长短期记忆网络(LSTM)。

RNNs维基解释:

https://en.wikipedia.org/wiki/Recurrent_neural_network

LSTM 维基解释:

https://en.wikipedia.org/wiki/Long_short-term_memory

LSTMs能够从时间序列数据中捕捉最重要的特征并进行关联建模。股票价格预测模型是关于对冲基金如何使用此类系统的典型案例,使用了Python编写的PyTorch框架进行训练,设计实验并绘制结果。

在介绍真实案例之前,我们先了解一下深度学习的基础:

  • 首先,引入深度学习这个抽象概念。
  • 其次,引入RNNs(或更具体地说是LSTMs)以及它们如何进行时间序列分析。
  • 接着,让读者熟悉适合深度学习模型的金融数据。
  • 接着,举一个实例来说明一支对冲基金如何使用深度学习预测股票价格。
  • 最后,就如何使用深度学习来提高对现有或新购对冲基金的表现提供可操作的建议。

介绍用深度学习进行交易的案例

金融行业最具挑战性和令人兴奋的任务之一便是:预测未来股价是上涨还是下跌。据我们所知,深度学习算法非常擅长解决复杂的任务,因此深度学习系统是否能够成功地解决预测未来价格这个问题是值得尝试的。

股价预测:

https://www.toptal.com/machine-learning/s-p-500-automated-trading

人工神经网络这个概念已经存在了很长一段时间,但由于硬件受限,一直无法进行深度学习方面的快速实验。十年前,Nvidia为其Tesla系列产品研发的高速计算的图形处理单元(GPUs)促进了深度学习网络的发展。除了在游戏和专业设计程序中提供更高质量的图形显示外,高度并行化的GPUs也可以计算其他数据,而且在很多情况下,它们的表现远优于CPUs。

Nvidia Tesla维基解释:

https://en.wikipedia.org/wiki/Nvidia_Tesla

在金融领域应用深度学习的科学论文并不多,但是金融公司对深度学习专家却有很大的需求,显然,这些公司认识到了深度学习的应用前景。

本文将尝试说明:为什么深度学习在用金融数据来构建深度学习系统时越来越受欢迎,同时也会介绍LSTMs这种特殊的递归神经网络。我们将概述如何使用递归神经网络解决金融相关问题。

本文还以对冲基金如何使用深度学习系统为例进行典型案例分析,并展示实验过程及结果。同时我们将分析如何提高深度学习系统性能,以及如何通过引进人才(如需要什么样背景的深度学习人才)来搭建应用于对冲基金的深度学习系统。

是什么使对冲基金与众不同

在我们进入这个问题的技术层面之前,我们需要解释的是什么使对冲基金与众不同。首先要明白的是,什么是对冲基金?

对冲基金是一种投资基金,金融组织从投资者筹集资金并将其投入短期和长期投资项目或者不同金融产品。它的形式一般是有限合伙企业或有限责任公司。

对冲基金的目标是最大化回报,回报是其在特定时间段内净值的收益或损失。普遍认为,投资风险越大,相应的回报或损失也越大。

为了获得良好的回报,对冲基金依赖各种投资策略,试图通过利用市场低效率来赚钱。由于对冲基金有普通投资基金所不允许的各种投资策略,其并未被认定为一般基金,也不像其他基金那样由国家监管。

因此他们不需要公布他们的投资策略和业务结果,这可能会使相关经营活动充满风险。虽然一些对冲基金产生的收益超过市场平均水平,但也有一些损失了资金。其中一些的损失无法挽回,也有一些对冲基金的结果是可逆的。

通过投资对冲基金,投资者可以增加基金的净值。不过,并不是所有人都可以投资于对冲基金,它只适用于少数富有的投资者。通常,想要参与对冲基金投资的人需要获得认证。

这意味着他们必须在金融监管法律方面拥有特殊地位。不同国家对于“特殊地位”的认定有所不同。通常,投资者的净资产需要非常高——不仅是个人,而且银行和大公司也可以在对冲基金中运作。该认证旨在让那些有必要投资知识的个人才能参与其中,从而保护经验不足的小型投资者免受风险。

美国是全球金融市场最发达的国家,因此本文主要参考美国的监管体系。在美利坚合众国,美国证券交易委员会(SEC)的D规则501规定了“认可投资者”一词。

根据这一规定,认可的投资者可以是:

  • 银行
  • 私营企业
  • 组织机构
  • 提供或出售证券的发行机构的董事,执行官和普通合伙人
  • 个人净资产或与该人配偶合资净值超过1,000,000美元的自然人
  • 自然人在最近两年每个年度的个人收入超过20万美元,或与该人的配偶每年在该年度的共同收入超过30万美元,并且当年的预期收入也达到相同的水平。
  • 信托资产总额超过5,000,000美元
  • 所有股权拥有者均为认可投资者的实体

对冲基金管理者管理对冲基金时必须要找到一种方法形成竞争优势从而取得成功,即需比竞争对手更具创造力,带来更大价值。这是一个非常有吸引力的职业选择,因为如果一个人擅长管理基金,就可能从中获利许多。

另一方面,如果很多对冲基金管理者的决定很糟糕,他们不仅不会获得收益,还会造成负面影响。最好的对冲基金管理者可以获得行业中薪酬最高的职位。

除了管理费外,对冲基金管理者还可以从资金获利中抽成。这种补偿方式使对冲基金管理者更积极地投资以获得更高的回报,但与此同时,这也会使投资者承担更多风险。

对冲基金简史

第一支对冲基金出现于1949年,由作家和社会学家Alfred Winslow Jones创立。1948,Alfred就当时的投资趋势发表了一篇文章。

他在资金管理方面获得了巨大的成功。利用他的投资创新筹集资金,这种投资创新现在被广泛称为多/空投股票。该策略目前在对冲基金中仍非常受欢迎。股票可以被买入(买入:买多)或卖出(卖出:卖空)。

当股价低但预计股价将会走高时,买入股票(多头),一旦达到高价时并卖出(空头),这正是Alfred所创理论的核心——对预计将升值的股票中持仓多头,对预计将下跌的股票持仓空头。

金融数据和数据集

金融数据属于时间序列数据。时间序列是一系列按时间顺序排列的数据点。通常,时间序列是连续、等间隔的时间序列:即离散时间序列数据。举例来说,海洋潮汐的高度,太阳黑子的数量以及道琼斯工业平均指数的每日收盘价都是时间序列。

这里的历史数据是指过去的时间序列数据。这是预测未来价格走向最重要和最有价值的部分。

网上有一些公开可用的数据集,但通常情况下,数据缺少很多特征——如间隔1天的数据,间隔1小时的数据或间隔1分钟的数据。

具有更丰富特征和更小时间间隔的数据集通常不公开,并且需要高价购买。

更小的间隔意味着更多的时间序列数据在一个固定的时间段内——一年内有365(或366)天,所以最多有365个(或366个)天数据点可用。每天有24小时,所以在一年内有8,760(或8,784)小时数据点,每天有86,400分钟,所以在一年内有525,600(或527,040)分钟的数据点可用。

越多的数据意味着越多的可用信息,也意味着可以更好地判断下一刻会发生什么——当然,如果数据包含足够的特征也可以泛化的很好。

在全球金融危机高峰时期,2007年至2008年的股价数据由于存在偏差,所以可能无法预测近期价格趋势。越小的时间间隔,在固定的时间间隔内就会有更多数据点,从而更容易地预测接下来会发生什么。

如果我们拥有n年内每一纳秒的数据,那么很容易预测下一纳秒会发生什么,同理在股市中,有了一定时间内的数据,在对接下来的情况作预测就容易的多。

当然,这也并不意味通过一系列数据后,只有所作的短期预测才是正确的,长期预测也可以是正确的。

每个短期预测都会产生误差,因此通过链接多个预测,长期预测最终将产生更大的误差而导致预测无效。以下是雅虎财经在线提供的间隔为1天的Google股票数据示例。

数据集中只有日期,开盘价,最高价,最低价和平仓价等五列数据,分别表示交易开放时证券首先交易的价格,即证券在给定交易日上达到的最高价格,给定交易日的最低价格以及当天交易证券的最终价格。

通常,此类数据集中还有两列——“调整后收盘价”和“成交量”,但它们在这里并不相关。调整后收盘价是指调整适用分割和股息分配后的收盘价,而成交量指是在给定时间段内在市场上交易的股票数量。

可以看到数据中缺失了部分日期。这些是证券交易所休市的日子(一般是在周末和假日)。

为了演示深度学习算法,休市的日子使用之前的交易日价格。例如,2010-01-16,2010-01-17,2010-01-18的收盘价格将全部为288.126007,因为这就是2010-01-15。对于我们的算法来说,数据没有间隙是非常重要的,所以我们不会混淆它。

深度学习算法可以通过周末和节假日的数据学习——比如说,了解到在五个工作日后,从最后一个工作日起,会有两天的平价。

这是一张自2010-01-04以来谷歌股价变动的图表。要注意的是,图表中只显示了交易日的变化趋势。

什么是深度学习?

深度学习基于数据表示学习,属于机器学习的一个分支。机器学习不是通过编程,而是从数据中学习得到的算法。它本质上是人工智能的一种方法。

深度学习已经应用到了多个领域:计算机视觉,语音识别,自然语言处理,机器翻译,而且在某些任务中,它的表现甚至超过人类。

深度神经网络是深度学习的核心,它最简单、最基本的例子就是前馈神经网络,如下图所示,一个基本的前馈神经网络包括输入层、输出层和隐藏层。

隐藏层是输入层和输出层之间的多个单独层。我们通常说如果一个神经网络隐藏层的个数大于1,那么这个网络就是深度的。

每一层都由不同数量的神经元组成。这个基本前馈神经网络中的层称之为线性层,线性层中的神经元仅仅将1-D(或者2-D,如果数据是分批输入网络的)的输入和合适的权重相乘并求和,作为1-D或2-D输出的最终结果。

前馈网络中通常引入激活函数(activation function)表示非线性关系,进而对更复杂的非线性问题建模。在前馈神经网络中,数据从输入层流向输出层,并不会反向传播。

神经元之间的连接是加权的。这些权重需要调整以便神经网络对于给定输入返回准确的输出。前馈网络将数据从输入空间映射到输出空间。隐藏层从前一层的特征中提取重要的和更抽象的特征。

通用深度学习管道和机器学习管道一样,都包含以下步骤:

  1. 数据采集。数据被分成3部分:训练集、验证集和测试集。
  2. 使用训练集进行多轮(每一轮包含多个迭代过程)训练DNN模型,并在每轮训练后使用验证集进行验证。
  3. 在不断训练和验证后,测试模型(一个带有固定参数的神经网络实例)。

训练神经网络实际上是通过反向传播算法结合随机梯度下降法来最小化损失函数,以此来不断调整神经元之间的权重。

除了通过学习过程确定的权重,深度学习算法通常还需要设置超参数——一类无法从学习过程获得,但需要在学习过程前确定的参数。如网络层数、网络层中的神经元数、网络层的类型、神经元的类型和初始权重都属于超参数。

在超参数设置中,第一存在硬件限制,目前,在一个GPU上设置一万亿个神经元是不可能的。第二超参数搜索问题属于组合爆炸;彻底搜索所有可能的超参数组合是不可能的,因为这个过程需要无限长的时间。

由于上述原因,超参数的设置通常是随机的,或者采用一些启发式方法和一些论文中提供的知名方法——本文稍后展示一个用于金融数据分析的循环神经网络的超参数设置实例,许多科学家和工程师已经证明循环神经网络在时间序列数据处理方面表现突出。

通常,验证一个超参数对于指定问题的效果是好是坏的最好方法就是做实验。

训练的目的是使得神经网络很好地拟合训练数据。每个训练步骤之后的模型验证和整个训练过程结束后的模型测试都是为了确定模型是否具有良好的泛化能力。

泛化能力强意味着神经网络模型对于新数据也能做出准确的预测。

关于模型选择有两个重要的术语:过拟合和欠拟合。如果一个神经网络对于它所训练的数据太复杂——如果它有太多的参数(网络层数太多,以及/或者网络层中有太多的神经元)——这个神经网络很有可能过拟合。

因为它有足够的能力去拟合所有数据,所以它能很好的适应训练数据,但是这个模型在验证集和测试集上的性能会很差。如果一个神经网络对于它所训练的数据太过简单,这个模型会欠拟合。

此时神经网络在训练集、验证集和测试集中性能都很差,因为它的能力不足以拟合训练数据并且进行泛化。在下图中我们用图形来解释这几个术语。

蓝色的线表示神经网络模型。第一张图表示当神经网络参数较少时,不能拟合训练数据和泛化的情况。第二张图表示在有最优参数数量时,神经网络对新的数据有较好的泛化能力。第三张图表示当神经网络参数太多时,这个模型过拟合训练数据,但是在验证集和测试集中表现不佳。

循环神经网络

神经网络中一个更复杂的版本是循环神经网络(Recurrent neural network)。与前馈神经网络不同,循环神经网络中的数据可以向任意方向流动。RNN可以更好的表示时间序列的相关性。一般循环神经网络的结构如下图所示。

一个循环神经元的表示如下图所示。在t时刻以X_{t}作为输入,返回t时的隐藏状态h_{t}作为输出,隐藏层输出反向传播回神经元。循环神经元展开后的表示如下图右侧部分。X_{t_0}表示t_{0}时刻的点,X_{t_1}表示t_{1}时刻的点,X_{t}表示t时刻的点。通过t_{0},t_{1},…,t_{n}时刻的输入X_{t_0},X_{t_1},…,X_{t_n}获得的输出就叫做隐藏输出,即h_{t_0},h_{t_1},…,h_{t_n}。

最有效的一个循环神经网络架构是LSTM结构。表示如下:

LSTMs与一般的循环神经网络结构一样,但是不同的是循环神经元的结构更为复杂。从上图可以看出,在一个LSTM单元内存在大量的计算。

在这篇文中,LSTM单元可以视为一个黑盒子,但是对于好奇的读者来说,可以看一篇阐述LSTMs内的计算以及其他一些内容的博客。

博客链接:

http://colah.github.io/posts/2015-08-Understanding-LSTMs/

我们把神经网络的输入称为“特征向量”。这是一个n维向量,其元素是特征:f_{0},f_{1},f_{2}…,f_{n}。现在,我们来解释循环神经网络是如何应用到与金融相关的任务上的。循环神经网络的输入是[X_{t_0},X_{t_1},X_{t_2},…,X_{t_n}]。这里让n=5。

我们采用Google连续5天(见上面开盘/高/低/收盘数据表)的股票收盘价,选择时间段为2010-01-04到2010-01-08,也就是[[311.35],[309.98],[302.16],[295.13],[299.06]]。这个例子中的特征向量是一维的。时间序列包含5个这样的特征向量。循环神经网络的输出是隐藏特征[h_{t_0},h_{t_1},h_{t_2},…,h_{t_n}]。

这些特征比输入特征[X_{t_0},X_{t_1},X_{t_2},…,X_{t_n}]更加抽象——LSTM需要学习到输入特征的重要部分并将它们映射到隐藏特征空间。

这些隐藏的抽象特征在下一个LSTM单元中传播并提供一组隐藏、更加抽象的特征,这些特征又可以在下一个LSTM单元中传播,以此类推。

在LSTMs连接序列之后,神经网络的最后一个组成部分是线性层(前一节介绍的简单前馈网络的构建部分),线性层将最后的LSTM的隐藏向量映射到一维空间的某个点上,这个点就是该网络的最终输出——时间周期X_{t+1}中预测的收盘价。在这个例子中应该是298.61。

注意:也有少量的LSTM将LSTMs的数量作为一个超参数,该参数通常由经验获得,当然也可以使用一些启发式的方法。如果数据不是很复杂,我们可以使用一些不那么复杂的结构来避免过拟合。如果数据比较复杂,我们使用一个复杂些的模型来防止欠拟合。

在训练过程中,预测的收盘价会跟实际价格比较,其差值采用反向传播算法和梯度下降优化算法(或者其他形式——具体来讲在这篇文章中将使用梯度下降优化算法的“Adam”版本),通过改变神经网络权重来最小化。

模型经过训练和测试之后,在以后的使用中,用户只需要给模型输入数据,模型将会返回预测价值(理想情况下,价格会非常接近未来的真实价格)。

还有一件事要需注意,通常来讲,在训练和测试部分,数据分批次通过网络,对于网络来讲只需要一次就可以计算出多个输出。

下图是这篇文章中使用的架构,包括2个LSTMs栈和一个线性层。

对冲基金算法实验

试着用一个简单的交易策略实现算法,描述如下:如果算法预测明天股价会上升,就买入n(在这个例子里n=1股该公司的股票(做多),否则就卖掉所持有的该公司的所有股票(做空)。

投资组合的初始价值(现金和股票的总价值)设定为100,000美元。每次交易行为将买入n股该公司(以Google为例)的股票或卖出所持有的该公司的所有股票。在初始时刻,系统对该给定公司股票的持有量为0。

需要时刻牢记的是这只是一个非常基础和简单的例子,并不适用于现实生活。若是想使这个模型在实际中很好地应用,仍需要进行很多的研发工作来调整模型。

有些在本例中被忽略的因素,在应用于实际场景时,都应当被纳入考虑中:比如,交易费用没有被考虑在模型之中。另外假设系统可以在每天的同一时间交易并且认为每一天,即使是周末或假期,都是交易日。

对于模型测试,我们使用回溯测试法。该方法利用历史数据,基于开发策略所定义的规则重建过去本该发生的交易。我们将数据集划分为两部分——第一部分作为训练集(作为历史交易数据),第二部分作为测试集(作为未来交易数据)。

模型在训练集上进行训练,训练完成后,我们在第二部分测试集上预测未来交易,从而检验训练得到的模型在不属于训练集的“未来交易”数据上的表现。

用于评价交易策略的指标是夏普比率(Sharpe ratio,年化值,假设一年中的每一天都是交易日,一年有365天:sqrt(365)*mean(returns)/std(returns))),其中收益率定义为p_{t}/p_{t-1} - 1, p_{t}是t时刻的价格。

夏普比率反映了投资组合的收益率与额外的风险之间的比率,所以夏普比率越大越好。一般地,对投资者来说,夏普比率大于1是令人满意的,大于2是非常不错的,而大于3则是极好的。

本例中,只选用来自雅虎的金融数据库(Yahoo Finance dataset)的谷歌历史价格的每日收盘价作为特征。虽然其他特征也有用,但是讨论该数据集中的其他特征(开盘价、最高价、最低价)是否起作用并不在本文讨论的范围之内。

其他一些不在该数据表中的特征可能也有用——例如某一特定分钟的新闻观点或某一天发生的重要事件。

然而,有时候很难将这些特征表示成对神经网络有用的输入并将其与现有特征结合起来。比如,对每一个给定时期,扩充特征向量并加入一个代表新闻观点或特朗普(Trump)在Tweet发表的观点是容易的(-1表示赞同,0表示中立,+1表示不赞同)。

但是,将特定的事件驱动的时刻(苏伊士运河的海盗事件,德克萨斯州炼油厂发现炸弹)加入特征向量并不容易,因为对于每一个这样的特定时刻,我们需要向特征向量中加入一个额外的元素,当该事件发生时令其为1,否则为0。

这样以来,为了考虑所有可能的特定时刻,我们需要向特征向量中加入无穷多个元素。

对那些更加复杂的数据,我们可以定义一些类别,对每一个特定时刻,确定它属于哪一个类别。我们也可以在系统中加入其他公司的股票特征,让模型学习不同公司股票价格之间的相关性。

此外,我们可以将循环层与另一种专门用于计算机视觉的神经网络——卷积神经网络(convolutional neural networks)结合起来以探究视觉特征是如何与某些公司股价相关联的,这也是一种很有趣的做法。

也许我们可以将使用相机拍摄的一张拥挤的火车站的照片作为一个特征,并将其加入神经网络,从而探究神经网络所“看”到的是否与某些公司的股价相关——或许在这个平庸且荒唐的例子中也存在着某些隐藏的信息。

下图展示了平均训练损失随时间逐渐减少的过程,这表明神经网络有足够的能力去拟合训练集。必须强调的是需要将数据进行标准化处理以保证深度学习算法能够收敛。

下图展示了平均测试损失随时间逐渐减少的过程,这表明神经网络对新数据有一定的泛化能力。

该算法具有贪心性质:如果它预测明天股价将上升,那么算法将会立即买入n=1份该公司的股票(如果投资组合中有足够的现金),否则它将会卖出所持有的该公司所有的股票(如果有的话)。

投资的时间段固定为300天。在300天以后,卖出所有股票。训练后的模型在新的数据上的模拟结果如下图所示。下图展现了随着每天做多/做空的交易(或不做交易),投资组合的价值随时间变化的过程。

上述投资模拟的夏普比率为1.48。300天后最终的投资组合的价值为100,263.79美元。如果我们只在第一天买入股票,并在300天后卖出,组合价值为99,988.41美元。

下图展示的是由于神经网络训练得不好而在300天的固定投资时期后亏损的情况。

这一模拟的夏普比率为-0.94。300天后投资组合的最终价值为99,868.36美元。

下面是一个有趣的例子:上述算法具有贪心性质并且仅仅估计了第二天的股价,并且仅仅基于这一预测值作出决策。但仍有可能需要连接多个预测值并且预测未来多期的价格。

比如,有了第一组输入[X_ground_truth_{t0},X_ground_truth_{t1},X_ground_truth_{t2},X_ground_truth_{t3},X_ground_truth_{t4}]和第一个输出[X_ground_truth_{t5}],我们可以把这一预测值输给神经网路来继续预测,即下一组输入为[X_ground_truth_{t1},X_ground_truth_{t2},X_ground_truth_{t3},X_ground_truth_{t4},X_ground_truth_{t5}],此时输出为[X_predicted_{t6}。

类似的,接着下一组输入为X_ground_truth_{t2},X_ground_truth_{t3},X_ground_truth_{t4},X_predicted_{t5},X_predicted_{t6}],由此可以得到[X_predicted_{t7}]等。

这里存在的问题是我们引入了一个预测误差,并且这一误差随着每一步新的预测而不断增加,最终导致了一个很差的长期的预测结果,如下图所示。最开始模型预测值有真实值具有相同的下降趋势,随后停滞,并且随着时间的推移变得越来越差。

对谷歌股票价格进行了简单的深度学习的分析,只要数据量足够大且质量足够好,这一模型几乎可以包含任何金融数据集。但是数据必须是可判别的,并且能够很好地描述和表示问题。

总结

如果模型对于大量的测试都表现得很好并有很强的泛化能力,那么它便可以使对冲基金管理者使用深度学习和算法交易策略来预测未来某一公司的股票价格。

对冲基金管理者可以向系统输入资金金额使其每天完成自动化交易。但是,让自动化交易算法在完全没有任何监督的情况下进行交易绝对不是一个好的选择。

因此对冲基金管理者应当有一些深度学习知识或者是雇佣一个懂得一些必要的深度学习技能的人来监管并判断这一系统是否是去了泛化能力而不适合用于交易了。

一旦系统失去了泛化能力,那么就有必要从头开始训练模型并重新进行测试(可以通过引入更多具有判别性的特征或新的信息——使用模型在上一次训练时没有用到的新的历史数据)。

有时候,数据质量差会导致深度学习模型不能够很好地训练和泛化。在这种情况下,一个经验丰富的深度学习工程师应当能够发现并扭转这种局面。

建立一个深度学习交易系统,你需要对冲基金数据科学家,机器学习/深度学习专家(包括科学家和工程师),熟悉机器学习/深度学习的研发工程师等等。

无论他们熟悉机器学习哪个领域的应用,不管是计算机视觉还是语音识别,老练的专家都能够将他们的经验很好地应用于金融领域。

归根结底,不管是哪方面的应用或产业,深度学习都有相同的基础,因此对有经验的人来说从一个主题切换到另一个都应该是简单的。

我们这里所描述的系统是最基本的,要应用于现实世界,需要进行更多的研发工作来增加收益。可能的系统改进方法包括开发更好的交易策略。

同时收集更多的数据来训练模型也是有帮助的,但是这样的数据一般都很贵。

缩短时间节点间的间隔也能够改善模型。使用更多的特征(如数据集中每一时点对应的新闻观点或重要的事件,尽管难以表示为适用于神经网络的形式)、大量的超参数的格点搜索优化以及循环神经网络结构的探索也能给模型带来改善。

此外,在做大量并行实验和处理大量数据(如果收集到了大量的数据)时,我们还需要更多的计算能力(更强的GPU是必需的)。

转载于:https://www.cnblogs.com/alan-blog-TsingHua/p/9951902.html

没有更多推荐了,返回首页