前言

本篇内容为第九章内容,随机森林模型。
为便于阅读,我将文章内容分为以下几个板块:

  1. 基础知识
  2. 实验内容
  3. 拓展研究
  4. 心得体会

其中,各板块的介绍如下:

  • 基础知识
  • 包含关于本章主题的个人学习理解,总结的知识点以及值得记录的代码及运行结果。
  • 实验内容
  • 这是本篇的主题实验部分,也是老师发的实验内容,在电脑上(jupyter notebook)运行成功之后导出为markdown格式。
  • 其中,主标题为每一章的小节内容
  • 如上图,主标题为PCA主成分分析与代码实现,次级标题为该文件内的子模块。每一个主标题下内容互不相同,也就是说,会出现两个主标题下均有相同python库引用的情况,为保证代码的完整性,在此予以保留。
  • 为表明确实是完成了课堂作业,故代码与老师给的代码大致相同,但markdown文本部分加入了自己的理解,同时,因为数据源不一定相同,运行结果和绘图也与教程相异,但实验本身是正确完整的。
  • 此外,一些老师发的相关的案(不在课程中心的实验,而是发到课程群中的案例,如 案例 航空公司客户价值分析)也会附在这一部分中。
  • 拓展研究
  • 这个部分是 自己在本课题实验之外尝试的拓展内容,包括代码和知识点,也有自己的实验
  • 心得体会

基础知识

实验内容

9.1.3 随机森林模型的代码实现

和决策树模型一样,随机森林模型既可以做分类分析,也可以做回归分析。

分别对应的模型为随机森林分类模型(RandomForestClassifier)及随机森林回归模型(RandomForestRegressor)。随机森林分类模型的基模型是分类决策树模型(详见5.1.2节),随机森林回归模型的基模型则是回归决策树模型(详见5.1.3节)。

# 随机森林分类模型简单代码演示如下所示:
from sklearn.ensemble import RandomForestClassifier
X = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
y = [0, 0, 0, 1, 1]

model = RandomForestClassifier(n_estimators=10, random_state=123)
model.fit(X, y)

print(model.predict([[5, 5]]))
[0]
# 随机森林回归模型简单代码演示如下所示:
from sklearn.ensemble import RandomForestRegressor
X = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
y = [1, 2, 3, 4, 5]

model = RandomForestRegressor(n_estimators=10, random_state=123)
model.fit(X, y)

print(model.predict([[5, 5]]))
[2.8]

9.2 量化金融 - 股票数据获取

9.2.1 股票基本数据获取

这里介绍一个免费的财经数据Python接口包:Tushare库,通过它我们能够免费地调用历史行情数据来进行分析。其官方地址为:http://tushare.org/
如果是想查看股价行情数据,可以访问相应网址:http://tushare.org/trading.html

1.Tushare库的基本介绍

推荐通过PIP安装法来安装Tushare库,以Windows系统为例,具体方法是:通过Win + R组合键调出运行框,输入cmd后回车,然后在弹出框中输入pip install tushare后按一下Enter回车键的方法来进行安装。如果在1.2.3节讲到的Jupyter Notebook编辑器中安装的话,只需要在代码框中输入!pip instll tushare(注意是英文格式下的!)然后运行该行代码框即可。

(1) 获得日线行情数据

import tushare as ts
df = ts.get_hist_data('000002', start='2018-01-01', end='2019-01-31')
df.head()
本接口即将停止更新,请尽快使用Pro版接口:https://tushare.pro/document/2



open

high

close

low

volume

price_change

p_change

ma5

ma10

ma20

v_ma5

v_ma10

v_ma20

turnover

date

注意,如果不写开始及结束日期,直接写ts.get_hist_data(‘000002’)会默认调取从当天往前3年的数据。此外,上面代码也可以简写成:

df = ts.get_hist_data('000002','2018-01-01', '2019-01-31')
df.head()



open

high

close

low

volume

price_change

p_change

ma5

ma10

ma20

v_ma5

v_ma10

v_ma20

date

2019-01-31

27.39

28.15

27.75

27.00

411857.59

0.54

1.99

26.800

26.153

25.641

426579.02

351523.31

320269.20

2019-01-30

26.70

27.82

27.21

26.63

592303.19

0.33

1.23

26.332

25.875

25.457

391193.72

334927.14

310794.00

2019-01-29

25.91

26.88

26.88

25.87

368071.62

0.82

3.15

25.952

25.696

25.292

302102.48

302443.43

293529.36

2019-01-28

26.20

26.62

26.06

25.86

308906.56

-0.04

-0.15

25.656

25.524

25.139

304355.52

302512.15

291266.32

2019-01-25

25.51

26.35

26.10

25.49

451756.16

0.69

2.71

25.574

25.420

25.008

293674.18

289949.63

293446.08

补充知识点:get_k_data()函数

因为get_hist_data()函数不仅获得了股票的基本价格信息,还获取了价格变化、均线价格等衍生变量,所以它最多也只能调取当天往前3年的数据,如果想调取超过3年的日线级别数据,得用ts.get_k_data()函数,它只获取股价的基本数据,代码如下:

df = ts.get_k_data('000002', start='2000-01-01', end='2019-01-31')
df.head()



date

open

close

high

low

volume

code

0

2000-01-04

0.584

0.614

0.620

0.572

45747.08

000002

1

2000-01-05

0.617

0.599

0.623

0.596

46136.73

000002

2

2000-01-06

0.596

0.627

0.632

0.587

71920.31

000002

3

2000-01-07

0.631

0.655

0.656

0.624

136349.36

000002

4

2000-01-10

0.673

0.721

0.721

0.665

142424.86

000002

通过get_k_data()函数获取的数据没有像get_hist_data()函数那样将日期默认设为行索引,这里的日期还是作为一个普通的列(date列),如果想把这里的date列转为行索引,可以使用设置索引的set_index()函数,代码如下:

df = df.set_index('date')  # 或者写成:df.set_index('date', inplace=True)
df.head()



open

close

high

low

volume

code

date

2000-01-04

0.584

0.614

0.620

0.572

45747.08

000002

2000-01-05

0.617

0.599

0.623

0.596

46136.73

000002

2000-01-06

0.596

0.627

0.632

0.587

71920.31

000002

2000-01-07

0.631

0.655

0.656

0.624

136349.36

000002

2000-01-10

0.673

0.721

0.721

0.665

142424.86

000002

(2) 获得分钟级别的数据

通过设置ktype参数可以获得分钟级别的数据,代码如下:

df = ts.get_hist_data('000002', ktype='5')
df.head()



open

high

close

low

volume

price_change

p_change

ma5

ma10

ma20

v_ma5

v_ma10

v_ma20

turnover

date

2020-01-03 15:00:00

32.06

32.07

32.06

32.05

3920.32

0.00

0.00

32.122

32.113

32.0350

15322.7

17669.5

13041.0

0.00

2020-01-03 14:55:00

32.11

32.11

32.07

32.03

8377.52

-0.04

-0.12

32.136

32.103

32.0290

19359.3

17817.5

13428.9

0.01

2020-01-03 14:50:00

32.20

32.21

32.12

32.11

13402.00

-0.08

-0.25

32.154

32.093

32.0175

23136.3

17962.0

13959.7

0.01

2020-01-03 14:45:00

32.16

32.21

32.20

32.12

24470.90

0.04

0.12

32.160

32.078

32.0050

24442.3

17137.9

13903.3

0.03

2020-01-03 14:40:00

32.13

32.18

32.16

32.13

26443.00

0.03

0.09

32.132

32.056

31.9880

23976.3

15128.1

13491.1

0.03

(3) 获得实时行情数据

通过如下代码可以实时取得股票当前报价和成交信息:

df = ts.get_realtime_quotes('000002') 
df



name

open

pre_close

price

high

low

bid

ask

volume

amount

...

a2_p

a3_v

a3_p

a4_v

a4_p

a5_v

a5_p

date

time

code

0

万 科A

32.710

32.560

32.050

32.810

31.780

32.040

32.050

80553629

2584309903.290

...

32.060

3005

32.070

119

32.080

344

32.090

2020-01-03

15:00:03

000002

1 rows × 33 columns

其运行结果就是当时的股价信息,如果收盘后运行的话获得的就是当日收盘价相关信息。如果觉得列数过多,可以通过DataFrame选取列的方法选取相应的列,代码如下:

df = df[['code','name','price','bid','ask','volume','amount','time']]
df



code

name

price

bid

ask

volume

amount

time

0

000002

万 科A

32.050

32.040

32.050

80553629

2584309903.290

15:00:03

如果想同时获得多个股票代码的实时数据,可以用如下代码:

df = ts.get_realtime_quotes(['000002','000980','000981'])
df



name

open

pre_close

price

high

low

bid

ask

volume

amount

...

a2_p

a3_v

a3_p

a4_v

a4_p

a5_v

a5_p

date

time

code

0

万 科A

32.710

32.560

32.050

32.810

31.780

32.040

32.050

80553629

2584309903.290

...

32.060

3005

32.070

119

32.080

344

32.090

2020-01-03

15:00:03

000002

1

众泰汽车

3.010

3.000

3.020

3.040

2.970

3.010

3.020

32495074

97566972.190

...

3.030

4849

3.040

3840

3.050

2811

3.060

2020-01-03

15:00:03

000980

2

ST银亿

1.870

1.890

1.810

1.920

1.800

1.810

1.820

40518670

74744476.400

...

1.830

2939

1.840

4163

1.850

1449

1.860

2020-01-03

15:00:03

000981

3 rows × 33 columns

(4) 获得分笔数据

通过如下代码可以获得历史分笔数据,分笔数据也即每笔成交的信息:

df = ts.get_tick_data('000002', date='2018-12-12', src='tt')
df.head()
D:\Anaconda\Anaconda\lib\site-packages\tushare\stock\trading.py:182: FutureWarning: read_table is deprecated, use read_csv instead, passing sep='\t'.
  skiprows=[0])



time

price

change

volume

amount

type

0

09:25:04

26.31

0.34

6077

15988903

卖盘

1

09:30:00

26.33

0.02

197

518651

买盘

2

09:30:04

26.33

0.00

4623

12173863

卖盘

3

09:30:06

26.34

0.01

391

1030134

买盘

4

09:30:09

26.35

0.01

3289

8664911

买盘

(5) 获得指数信息

通过如下代码可以获得上证指数等指数信息:

df = ts.get_index()
df.head()  # 目前的tushare获得的指数的列名有点错乱-2020-01-04备注



code

name

change

open

preclose

close

high

low

volume

amount

1

00上证指数

3089.0220

0.33

3085.1976

3083.7858

3093.8192

3074.5178

0.0

2.899917e+11

0.0

2

00A股指数

3236.7077

0.33

3232.6892

3231.1885

3241.7436

3221.4906

0.0

2.899041e+11

0.0

3

00B股指数

261.0510

0.00

261.1236

261.7619

261.7619

260.2429

0.0

8.764934e+07

0.0

8

00综合指数

3006.0295

0.39

2999.1744

3006.5318

3018.1699

2998.4266

0.0

6.499701e+10

0.0

9

0上证380

4885.0267

0.23

4881.7235

4879.5471

4890.8838

4858.4325

0.0

5.888844e+10

0.0

9.2.2 股票衍生变量生成

1.生成股票基本数据

这里首先通过上一节的get_k_data()函数获取从2015-01-01到2019-12-31的股票基本数据:

df = ts.get_k_data('000002',start='2015-01-01',end='2019-12-31')
df.head()



date

open

close

high

low

volume

code

0

2015-01-05

12.436

12.885

13.214

12.289

6560835.0

000002

1

2015-01-06

12.617

12.410

12.954

12.142

3346346.0

000002

2

2015-01-07

12.324

12.298

12.531

12.099

2642051.0

000002

3

2015-01-08

12.375

11.745

12.419

11.632

2639394.0

000002

4

2015-01-09

11.701

11.624

12.289

11.485

3294584.0

000002

# 通过set_index()函数可以将日期列设置为行索引:
df = df.set_index('date')
df.head()



open

close

high

low

volume

code

date

2015-01-05

12.436

12.885

13.214

12.289

6560835.0

000002

2015-01-06

12.617

12.410

12.954

12.142

3346346.0

000002

2015-01-07

12.324

12.298

12.531

12.099

2642051.0

000002

2015-01-08

12.375

11.745

12.419

11.632

2639394.0

000002

2015-01-09

11.701

11.624

12.289

11.485

3294584.0

000002

2.简单衍生变量的计算

通过如下代码我们可以先构造一些简单的衍生变量:

df['close-open'] = (df['close'] - df['open'])/df['open']
df['high-low'] = (df['high'] - df['low'])/df['low']

df['pre_close'] = df['close'].shift(1)  # 该列所有往下移一行形成昨日收盘价
df['price_change'] = df['close']-df['pre_close']
df['p_change'] = (df['close']-df['pre_close'])/df['pre_close']*100

df.head()



open

close

high

low

volume

code

close-open

high-low

pre_close

price_change

p_change

date

2015-01-05

12.436

12.885

13.214

12.289

6560835.0

000002

0.036105

0.075271

NaN

NaN

NaN

2015-01-06

12.617

12.410

12.954

12.142

3346346.0

000002

-0.016406

0.066875

12.885

-0.475

-3.686457

2015-01-07

12.324

12.298

12.531

12.099

2642051.0

000002

-0.002110

0.035705

12.410

-0.112

-0.902498

2015-01-08

12.375

11.745

12.419

11.632

2639394.0

000002

-0.050909

0.067658

12.298

-0.553

-4.496666

2015-01-09

11.701

11.624

12.289

11.485

3294584.0

000002

-0.006581

0.070004

11.745

-0.121

-1.030226

3.移动平均线指标MA值

通过如下代码可以获得股价的5日移动平均值和10日移动平均值:

df['MA5'] = df['close'].rolling(5).mean()
df['MA10'] = df['close'].rolling(10).mean()

df.head(15)  # head(15)表示展示前15行,因为要展示10行以上,才能看到MA10有值



open

close

high

low

volume

code

close-open

high-low

pre_close

price_change

p_change

MA5

MA10

date

2015-01-05

12.436

12.885

13.214

12.289

6560835.0

000002

0.036105

0.075271

NaN

NaN

NaN

NaN

NaN

2015-01-06

12.617

12.410

12.954

12.142

3346346.0

000002

-0.016406

0.066875

12.885

-0.475

-3.686457

NaN

NaN

2015-01-07

12.324

12.298

12.531

12.099

2642051.0

000002

-0.002110

0.035705

12.410

-0.112

-0.902498

NaN

NaN

2015-01-08

12.375

11.745

12.419

11.632

2639394.0

000002

-0.050909

0.067658

12.298

-0.553

-4.496666

NaN

NaN

2015-01-09

11.701

11.624

12.289

11.485

3294584.0

000002

-0.006581

0.070004

11.745

-0.121

-1.030226

12.1924

NaN

2015-01-12

11.511

11.338

11.511

11.019

2436341.0

000002

-0.015029

0.044650

11.624

-0.286

-2.460427

11.8830

NaN

2015-01-13

11.278

11.295

11.563

11.209

1664610.0

000002

0.001507

0.031582

11.338

-0.043

-0.379256

11.6600

NaN

2015-01-14

11.295

11.321

11.494

11.122

1646818.0

000002

0.002302

0.033447

11.295

0.026

0.230190

11.4646

NaN

2015-01-15

11.347

11.900

11.952

11.235

2429686.0

000002

0.048735

0.063818

11.321

0.579

5.114389

11.4956

NaN

2015-01-16

11.900

11.684

11.900

11.572

2129475.0

000002

-0.018151

0.028344

11.900

-0.216

-1.815126

11.5076

11.8500

2015-01-19

10.803

10.517

11.148

10.517

3603625.0

000002

-0.026474

0.059998

11.684

-1.167

-9.988018

11.3434

11.6132

2015-01-20

10.543

10.673

10.889

10.422

2914688.0

000002

0.012330

0.044809

10.517

0.156

1.483313

11.2190

11.4395

2015-01-21

10.656

11.278

11.407

10.457

3555294.0

000002

0.058371

0.090848

10.673

0.605

5.668509

11.2104

11.3375

2015-01-22

11.252

11.736

11.796

11.166

3224727.0

000002

0.043015

0.056421

11.278

0.458

4.061004

11.1776

11.3366

2015-01-23

11.727

12.030

12.177

11.494

3310408.0

000002

0.025838

0.059422

11.736

0.294

2.505112

11.2468

11.3772

# 删除空值
df.dropna(inplace=True)  # 删除空值行,也可以写成df = df.dropna()
df.head()



open

close

high

low

volume

code

close-open

high-low

pre_close

price_change

p_change

MA5

MA10

date

2015-01-16

11.900

11.684

11.900

11.572

2129475.0

000002

-0.018151

0.028344

11.900

-0.216

-1.815126

11.5076

11.8500

2015-01-19

10.803

10.517

11.148

10.517

3603625.0

000002

-0.026474

0.059998

11.684

-1.167

-9.988018

11.3434

11.6132

2015-01-20

10.543

10.673

10.889

10.422

2914688.0

000002

0.012330

0.044809

10.517

0.156

1.483313

11.2190

11.4395

2015-01-21

10.656

11.278

11.407

10.457

3555294.0

000002

0.058371

0.090848

10.673

0.605

5.668509

11.2104

11.3375

2015-01-22

11.252

11.736

11.796

11.166

3224727.0

000002

0.043015

0.056421

11.278

0.458

4.061004

11.1776

11.3366

4.股票衍生变量生成库:TA-Lib库的安装

下面要讲的衍生变量指标都是通过股票衍生变量生成库:TA-Lib库生成的,所以这里我们先讲解一下如何安装Ta-Lib库:

以Windows操作系统为例,如果你的系统是Windows的64位系统,直接使用pip install talib语句会报错,原因在于python pip源中TA-Lib是32位的,不能安装在64位系统平台上。

正确的方法是下载64位的安装包后本地安装,下载推荐使用加州大学的python扩展库,地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/

进入网址后Ctrl + F键搜索“ta_lib”,如下图所示,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FpvDHWnj-1681175692727)( https://uploader.shimo.im/f/rd7iXLJw6RMZPkbV.png!thumbnail)]

选择对应的文件TA_Lib-0.4.17-cp37-cp37m-win_amd64.whl(cp后的37表示的是Python3.7版本)下载到自己选择的文件夹,读者在下载时也要根据自己Python的版本进行下载。

如何查看自己Python的版本,可以通过Win + R键调出运行框,然后输入cmd,在弹出界面中输入python,然后按一下Enter回车键即可查看相关版本,如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6KXw9yAF-1681175692728)( https://uploader.shimo.im/f/90luFuZqHt46OZko.png)]

下载完成后,在自己选择的文件夹中(例如笔者保存在的文件夹“E:\机器学习与大数据分析\随机森林”),如下图所示,在搜索框中输入cmd后按一下Enter回车键搜索:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wp2cI7Zm-1681175692728)( https://uploader.shimo.im/f/EnabNoMQKT0tYdaz.png!thumbnail)]

在弹出框中输入如下内容,然后Enter回车键安装即可。

pip install TA_Lib-0.4.17-cp37-cp37m-win_amd64.whl

5.通过TA-Lib库生成相对强弱指标RSI值

import talib
df['RSI'] = talib.RSI(df['close'], timeperiod=12)

6.通过TA-Lib库生成动量指标MOM值

df['MOM'] = talib.MOM(df['close'], timeperiod=5)

7.通过TA-Lib库生成指数移动平均值EMA

df['EMA12'] = talib.EMA(df['close'], timeperiod=12)  # 12日指数移动平均线
df['EMA26'] = talib.EMA(df['close'], timeperiod=26)  # 26日指数移动平均线

8.通过TA-Lib库生成异同移动平均线MACD值

df['MACD'], df['MACDsignal'], df['MACDhist'] = talib.MACD(df['close'], fastperiod=12, slowperiod=26, signalperiod=9)
df.dropna(inplace=True)  # 删除空行
df.tail()  # 和head()相对,通过tail()函数可以查看后五行



open

close

high

low

volume

code

close-open

high-low

pre_close

price_change

p_change

MA5

MA10

RSI

MOM

EMA12

EMA26

MACD

MACDsignal

MACDhist

date

2019-12-25

30.40

30.29

30.63

30.18

685037.0

000002

-0.003618

0.014911

30.38

-0.09

-0.296248

30.878

30.075

63.075563

-0.02

29.908556

28.973211

0.935345

0.772958

0.162387

2019-12-26

30.50

31.12

31.30

30.50

888790.0

000002

0.020328

0.026230

30.29

0.83

2.740178

30.896

30.387

68.890164

0.09

30.094932

29.132233

0.962699

0.810906

0.151793

2019-12-27

31.23

31.00

31.32

30.81

703096.0

000002

-0.007365

0.016553

31.12

-0.12

-0.385604

30.760

30.672

67.220611

-0.68

30.234173

29.270586

0.963587

0.841442

0.122145

2019-12-30

31.35

31.57

31.79

31.02

915751.0

000002

0.007018

0.024823

31.00

0.57

1.838710

30.872

30.884

70.877814

0.56

30.439685

29.440913

0.998772

0.872908

0.125864

2019-12-31

31.35

32.18

32.45

31.32

663497.0

000002

0.026475

0.036079

31.57

0.61

1.932214

31.232

31.057

74.233951

1.80

30.707426

29.643808

1.063618

0.911050

0.152567

补充内容:Talib库的一些验证

RSI指标的验证

import pandas as pd
import talib

data = pd.DataFrame()
data['close'] = [10, 12, 11, 13, 12, 14, 13]
data['RSI'] = talib.RSI(data['close'], timeperiod=6)

data



close

RSI

0

10

NaN

1

12

NaN

2

11

NaN

3

13

NaN

4

12

NaN

5

14

NaN

6

13

66.666667

9.3 量化金融 - 股票涨跌预测模型搭建

9.3.1 多因子模型搭建

1.引入之后需要用到的库

import tushare as ts  # 股票基本数据相关库
import numpy as np  # 科学计算相关库
import pandas as pd  # 科学计算相关库  
import talib  # 股票衍生变量数据相关库
import matplotlib.pyplot as plt  # 引入绘图相关库
from sklearn.ensemble import RandomForestClassifier  # 引入分类决策树模型
from sklearn.metrics import accuracy_score  # 引入准确度评分函数
import warnings
warnings.filterwarnings("ignore") # 忽略警告信息,警告非报错,不影响代码执行

2.股票数据处理与衍生变量生成

我们这里将8.2节股票基本数据和股票衍生变量数据的相关代码汇总,方便之后的股票涨跌预测模型的搭建:

# 1.股票基本数据获取
df = ts.get_k_data('000002',start='2015-01-01',end='2019-12-31')
df = df.set_index('date')  # 设置日期为索引

# 2.简单衍生变量构造
df['close-open'] = (df['close'] - df['open'])/df['open']
df['high-low'] = (df['high'] - df['low'])/df['low']

df['pre_close'] = df['close'].shift(1)  # 该列所有往下移一行形成昨日收盘价
df['price_change'] = df['close']-df['pre_close']
df['p_change'] = (df['close']-df['pre_close'])/df['pre_close']*100

# 3.移动平均线相关数据构造
df['MA5'] = df['close'].rolling(5).mean()
df['MA10'] = df['close'].rolling(10).mean()
df.dropna(inplace=True)  # 删除空值

# 4.通过Ta_lib库构造衍生变量
df['RSI'] = talib.RSI(df['close'], timeperiod=12)  # 相对强弱指标
df['MOM'] = talib.MOM(df['close'], timeperiod=5)  # 动量指标
df['EMA12'] = talib.EMA(df['close'], timeperiod=12)  # 12日指数移动平均线
df['EMA26'] = talib.EMA(df['close'], timeperiod=26)  # 26日指数移动平均线
df['MACD'], df['MACDsignal'], df['MACDhist'] = talib.MACD(df['close'], fastperiod=12, slowperiod=26, signalperiod=9)  # MACD值
df.dropna(inplace=True)  # 删除空值
本接口即将停止更新,请尽快使用Pro版接口:https://tushare.pro/document/2
# 查看此时的df后五行
df.tail()



open

close

high

low

volume

code

close-open

high-low

pre_close

price_change

p_change

MA5

MA10

RSI

MOM

EMA12

EMA26

MACD

MACDsignal

MACDhist

date

2019-12-25

27.165

27.055

27.395

26.945

685037.0

000002

-0.004049

0.016701

27.145

-0.09

-0.331553

27.643

26.840

63.081344

-0.02

26.673555

25.737103

0.936452

0.774585

0.161867

2019-12-26

27.265

27.885

28.065

27.265

888790.0

000002

0.022740

0.029342

27.055

0.83

3.067825

27.661

27.152

68.895291

0.09

26.859932

25.896207

0.963725

0.812413

0.151311

2019-12-27

27.995

27.765

28.085

27.575

703096.0

000002

-0.008216

0.018495

27.885

-0.12

-0.430339

27.525

27.437

67.225542

-0.68

26.999173

26.034636

0.964537

0.842838

0.121699

2019-12-30

28.115

28.335

28.555

27.785

915751.0

000002

0.007825

0.027713

27.765

0.57

2.052944

27.637

27.649

70.882335

0.56

27.204685

26.205033

0.999651

0.874201

0.125451

2019-12-31

28.115

28.945

29.215

28.085

663497.0

000002

0.029522

0.040235

28.335

0.61

2.152815

27.997

27.822

74.238064

1.80

27.472426

26.407994

1.064432

0.912247

0.152185

3.特征变量和目标变量提取

X = df[['close', 'volume', 'close-open', 'MA5', 'MA10', 'high-low', 'RSI', 'MOM', 'EMA12', 'MACD', 'MACDsignal', 'MACDhist']]
y = np.where(df['price_change'].shift(-1)> 0, 1, -1)

首先强调最核心的一点:应该是今天的股价信息预测下一天的股价涨跌情况,所以y应该是下一天的股价变化情况。

其中Numpy库中的where()函数的使用方法如下所示:
np.where(判断条件,满足条件的赋值,不满足条件的赋值)

其中df[‘price_change’].shift(-1)则是利用shift()函数将price_change(股价变化)这一列往上移动一行,这样就获得了每一行对应的下一天股价涨跌情况。

因此这里的判断条件就是下一天股价是否大于0,如果下一天股价涨了的我们则y赋值为数字1,下一天股价跌了的,则y赋值为数字-1。这个下一天的股价涨跌情况就是我们根据当天股票基本数据以及衍生变量预测的内容。

3.训练集和测试集数据划分

接下来,我们要将原始数据集进行分割,我们要注意到一点,训练集与测试集的划分要按照时间序列划分,而不是像之前利用train_test_split()函数进行划分。原因在于股票价格的变化趋势具有时间性,如果我们随机划分,则会破坏时间性特征,因为我们是根据当天数据来预测下一天的股价涨跌情况,而不是任意一天的股票数据来预测下一天的股价涨跌情况。
因此,我们将前90%的数据作为训练集,后10%的数据作为测试集,代码如下:

X_length = X.shape[0]  # shape属性获取X的行数和列数,shape[0]即表示行数 
split = int(X_length * 0.9)

X_train, X_test = X[:split], X[split:]
y_train, y_test = y[:split], y[split:]

4.模型搭建

model = RandomForestClassifier(max_depth=3, n_estimators=10, min_samples_leaf=10, random_state=1)
model.fit(X_train, y_train)


RandomForestClassifier(max_depth=3, min_samples_leaf=10, n_estimators=10,

random_state=1)</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class="sk-container" hidden><div class="sk-item"><div class="sk-estimator sk-toggleable"><input class="sk-toggleable__control sk-hidden--visually" id="sk-estimator-id-1" type="checkbox" checked><label for="sk-estimator-id-1" class="sk-toggleable__label sk-toggleable__label-arrow">RandomForestClassifier</label><div class="sk-toggleable__content"><pre>RandomForestClassifier(max_depth=3, min_samples_leaf=10, n_estimators=10,
                   random_state=1)</pre></div></div></div></div></div>


9.3.2 模型使用与评估

1.预测下一天的涨跌情况

y_pred = model.predict(X_test)
print(y_pred)
[-1  1 -1  1  1  1  1  1  1  1  1  1  1  1  1  1 -1  1  1  1  1  1  1  1
  1  1  1  1  1  1 -1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
  1  1  1  1  1  1 -1 -1 -1  1  1  1  1  1  1  1  1  1  1  1  1 -1 -1 -1
 -1 -1 -1 -1 -1 -1 -1 -1 -1]
a = pd.DataFrame()  # 创建一个空DataFrame 
a['预测值'] = list(y_pred)
a['实际值'] = list(y_test)
a.head()



预测值

实际值

0

-1

-1

1

1

-1

2

-1

-1

3

1

-1

4

1

1

# 查看预测概率
y_pred_proba = model.predict_proba(X_test)
y_pred_proba[0:5]
array([[0.53462409, 0.46537591],
       [0.49852513, 0.50147487],
       [0.53687766, 0.46312234],
       [0.49733765, 0.50266235],
       [0.49733765, 0.50266235]])

2.模型准确度评估

from sklearn.metrics import accuracy_score
score = accuracy_score(y_pred, y_test)
print(score)
0.5428571428571428
# 此外,我们还可以通过模型自带的score()函数记性打分,代码如下:
model.score(X_test, y_test)
0.5428571428571428

3.分析数据特征的重要性

model.feature_importances_
array([0.15132672, 0.09957677, 0.05021545, 0.06514831, 0.079073  ,
       0.11447561, 0.04576496, 0.17559964, 0.04713332, 0.07061667,
       0.08866083, 0.01240873])
# 通过如下代码可以更好的展示特征及其特征重要性:
features = X.columns  
importances = model.feature_importances_
a = pd.DataFrame()
a['特征'] = features
a['特征重要性'] = importances
a = a.sort_values('特征重要性', ascending=False)
a



特征

特征重要性

7

MOM

0.175600

0

close

0.151327

5

high-low

0.114476

1

volume

0.099577

10

MACDsignal

0.088661

4

MA10

0.079073

9

MACD

0.070617

3

MA5

0.065148

2

close-open

0.050215

8

EMA12

0.047133

6

RSI

0.045765

11

MACDhist

0.012409

9.3.3 参数调优

from sklearn.model_selection import GridSearchCV  # 网格搜索合适的超参数
# 指定分类器中参数的范围
parameters = {'n_estimators':[5, 10, 20], 'max_depth':[2, 3, 4, 5], 'min_samples_leaf':[5, 10, 20, 30]}
new_model = RandomForestClassifier(random_state=1)  # 构建分类器
grid_search = GridSearchCV(new_model, parameters, cv=6, scoring='accuracy')  # cv=6表示交叉验证6次,scoring='roc_auc'表示以ROC曲线的AUC评分作为模型评价准则, 默认为'accuracy', 即按准确度评分
grid_search.fit(X_train, y_train)  # 传入数据
grid_search.best_params_  # 输出参数的最优值
{'max_depth': 2, 'min_samples_leaf': 20, 'n_estimators': 10}

9.3.4 收益回测曲线绘制

X_test['prediction'] = model.predict(X_test)
X_test['p_change'] = (X_test['close'] - X_test['close'].shift(1)) / X_test['close'].shift(1)

X_test['origin'] = (X_test['p_change'] + 1).cumprod()
X_test['strategy'] = (X_test['prediction'].shift(1) * X_test['p_change'] + 1).cumprod()

X_test[['strategy', 'origin']].tail()



strategy

origin

date

2019-12-25

1.248484

1.059319

2019-12-26

1.210183

1.091817

2019-12-27

1.215391

1.087118

2019-12-30

1.190439

1.109436

2019-12-31

1.164811

1.133320

# 通过如下代码将收益情况删除空值后可视化,并设置X轴刻度自动倾斜:
X_test[['strategy', 'origin']].dropna().plot()
plt.gcf().autofmt_xdate()
plt.show()


python 随机森林回归器模型评价 随机森林回归方程_python 随机森林回归器模型评价

拓展研究

分类器的不确定度估计

决策函数

对于二分类的情况,decision_function返回值的形状是(n_samples,),为每个样本都返回一个浮点数:

from sklearn.ensemble import GradientBoostingClassifier
from sklearn.datasets import make_circles
X,y=make_circles(noise=0.25,factor=0.5,random_state=1)

y_named=np.array(["blue","red"])[y]

X_train,X_test,y_train_named,y_test_named,y_train,y_test=train_test_split(X,y_named,y,random_state=0)

gbrt=GradientBoostingClassifier(random_state=0)
gbrt.fit(X_train,y_train_named)
print("X_test.shape:{}".format(X_test.shape))
print("Decision function shape:{}".format(gbrt.decision_function(X_test).shape))

X_test.shape:(25, 2)
Decision function shape:(25,)

decision_function=gbrt.decision_function(X_test)

fig,axes=plt.subplots(1,2,figsize=(13,5))
mglearn.tools.plot_2d_separator(gbrt,X,ax=axes[0],alpha=.4,fill=True,cm=mglearn.cm2)
scores_image=mglearn.tools.plot_2d_scores(gbrt,X,ax=axes[1],alpha=.4,cm=mglearn.ReBl)

for ax in axes:
    mglearn.discrete_scatter(X_test[:,0],X_test[:,1],y_test,markers='^',ax=ax)
    mglearn.discrete_scatter(X_train[:,0],X_train[:,1],y_train,markers='o',ax=ax)
    ax.set_xlabel("Feature 0")
    ax.set_ylabel("Feature 1")
cbar=plt.colorbar(scores_image,ax=axes.tolist())
axes[0].legend(["Test class 0","Test class 1","Train class 0","Train class 1"],ncol=4,loc=(.1,1.1))

梯度提升模型在一个二维玩具数据集上的决策边界(左)和决策函数(右)

python 随机森林回归器模型评价 随机森林回归方程_数据_02