查看原文
其他

超级攻略!Pandas \ NumPy \ Matrix 用于金融数据准备

数据准备是一项必须具备的技术,是一个迭代且灵活的过程,可以用于查找、组合、清理、转换和共享数据集,包括用于分析/商业智能(BI)、数据科学/机器学习(ML)和自主数据集成中。具体来说,数据准备是在处理和分析之前对原始数据进行清洗和转换的过程,通常包括重新格式化数据、更正数据和组合数据集来丰富数据等。

本次数据分析实战系列运用股市金融数据,并对其进行一些列分析处理。处理金融数据是量化分析的基础,当然方法都是通用的,换做其他数据也同样适用。本文回顾数据分析常用模块PandasNumPy,回顾DataFramearraymatrix 基本操作。

股市数据获取的几个模块

Tushare

Tushare是一个免费、开源的python财经数据接口包。主要实现对股票等金融数据从数据采集、清洗加工到数据存储的过程,能够为金融分析人员提供快速、整洁、和多样的便于分析的数据,为他们在数据获取方面极大地减轻工作量,使他们更加专注于策略和模型的研究与实现上。

  • 首先使用pip安装第三方依赖库 tushare 下载股市数据。(国内)
pip install tushare -i https://pypi.douban.com/simple/
  • 然后在tushare.pro注册用户,注意获取你自己的token。使用daily函数获取日线数据。
# 导入tushare库
import tushare as ts
# 设置token
ts.set_token('your token here')
# 初始化pro接口
pro = ts.pro_api()
# 获取日线数据
df = pro.daily(ts_code='000001.SZ', start_date='20180701', end_date='20180718'

Baostock

证券宝(http://www.baostock.com)是一个免费、开源的证券数据平台(无需注册)。提供大量准确、完整的证券历史行情数据、上市公司财务数据等。通过python API获取证券数据信息,满足量化交易投资者、数量金融爱好者、计量经济从业者数据需求。

  • 首先使用pip安装第三方依赖库 baostock 下载股市数据。(国内)
pip install baostock -i https://pypi.douban.com/simple/
  • 然后使用query_history_k_data_plus函数获取日线数据
import baostock as bs
import pandas as pd

# 登陆系统
lg = bs.login()
# 获取沪深A股历史K线数据
rs_result = bs.query_history_k_data_plus("sh.600000",
                                         fields="date,open,high, low, close,preclose,volume,amount,adjustflag",
                                         start_date='2017-07-01'
                                         end_date='2017-12-31'
                                         frequency="d"
                                         adjustflag="3")
df_result = rs_result.get_data()
# 登出系统
bs.logout()

Yfinance

yfinance的老版本是fix_yahoo_finance,二者都可以使用,推荐使用新版本。

  • 首先使用pip安装第三方依赖库 fix_yahoo_finance 下载yahoo股市数据。(国外)
pip install fix_yahoo_finance -i https://pypi.douban.com/simple/

如果发生报错:ModuleNotFoundError: No module named 'yfinance',则需要事先安装'yfinance',最新版本已经将fix_yahoo_finance调整'yfinance'

pip install yfinance -i https://pypi.douban.com/simple/
  • 然后使用pdr_override函数获取日线数据
import yfinance as yf
# 输入
symbol = 'AMD'
start = '2014-01-01'
end = '2018-08-27'

dataset=yf.pdr_override(symbol,start,end)
dataset.head()

下面开始本节主要内容,运用数据处理最常用的第三方模块PandasNumPy获取数据,为后续数据分析、机器学习做数据准备。

pandas

pandas 是基于NumPy 的一种工具,该工具是为解决数据分析任务而创建的。Pandas 纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具。pandas提供了大量能使我们快速便捷地处理数据的函数和方法。你很快就会发现,它是使Python成为强大而高效的数据分析环境的重要因素之一。

# Pandas Library
>>> import pandas as pd
>>> import warnings
>>> warnings.filterwarnings("ignore")

获取中国平安股票数据

>>> import baostock as bs
# 登陆系统
>>> lg = bs.login()
# 获取沪深A股历史K线数据
>>> rs_result = bs.query_history_k_data_plus("sh.601318",
                        fields="date,open,high,low,close,volume"
                        start_date='2018-01-01'
                        end_date='2021-03-31'
                        frequency="d"
                        adjustflag="3")
>>> df_result = rs_result.get_data()
# 登出系统 
>>> bs.logout()
login success!
logout success!
<baostock.data.resultset.ResultData at 0x28d05a44ac8>

>>> df_result.head()

获取腾讯股票数据

>>> import yfinance as yf

>>> symbol = 'TCEHY'
>>> start = '2016-01-01'
>>> end = '2021-03-31'
>>> yf.pdr_override()

>>> dataset = yf.download(symbol,start,end)
[*********************100%***********************]  1 of 1 completed

>>> dataset.head()

查看尾部数据

dataset.tail()
>>> dataset.shape
(1320, 6)

滚动窗口计算

dataset.rolling(window=5).mean() # 求最后4行的均值


  • 函数解析
dataset.rolling(
    window,
    min_periods=None,
    center=False,
    win_type=None,
    on=None,
    axis=0,
    closed=None,)

提供滚动窗口计算。

window:也可以省略不写。表示时间窗的大小,注意有两种形式(int or offset)。如果使用int,则数值表示计算统计量的观测值的数量即向前几个数据。 如果是offset类型,表示时间窗的大小。

min_periods:每个窗口最少包含的观测值数量,小于这个值的窗口结果为NA。值可以是int,默认None。offset情况下,默认为1。

center: 把窗口的标签设置为居中。布尔型,默认False,居右

win_type: 窗口的类型。截取窗的各种函数。字符串类型,默认为None。各种类型

on: 可选参数。对于dataframe而言,指定要计算滚动窗口的列。值为列名。

axis: int、字符串,默认为0,即对列进行计算

closed:定义区间的开闭,支持int类型的window。对于offset类型默认是左开右闭的即默认为right。可以根据情况指定为left both等。

指数加权函数ewm

>>> dataset['ewm'] = dataset['Adj Close'].ewm(span=20,
                                              min_periods=0,
                                              adjust=False,
                                              ignore_na=False).mean()
>>> dataset.head()


  • 函数解析
DataFrame.ewm(com=None
            span=None
            halflife=None
            alpha=None
            min_periods=0
            adjust=True
            ignore_na=False
            axis=0
            times=None)

提供指数加权(EW)函数。可用EW功能:mean()var()std()corr()cov()参数:comspanhalflife,或alpha必须提供。

com float, optional  
根据质心指定衰减,

span float, optional  
跨度,根据跨度指定衰减,

halflife float, str, timedelta, optional  
半衰期,根据半衰期指定减,

如果times指定,则观察值衰减到其值一半的时间单位(str或timedelta)。仅适用于mean() ,半衰期值不适用于其他功能。

alpha float, optional  
直接地指定平滑系数

min_periods int, default 0  
窗口中具有值的最小观察数(否则结果为NA)。

adjust bool, default True  
调整,在开始期间除以递减的调整因子,以解决相对权重的不平衡问题(将EWMA视为移动平均值)。

  • adjust=True(默认)时,EW功能是使用权重计算的 α。例如,该系列的EW移动平均值 将会

  • adjust=False为时,将以递归方式计算指数加权函数:

ignore_na bool, default False  
算权重时忽略缺失值;指定True重现0.15.0之前的行为。

  • ignore_na=False(默认)时,权重基于绝对位置。例如,权重  用于计算 的最终加权平均数,如果adjust=True,则权重分别是 和 1。如果adjust=False,权重分别是

  • ignore_na=True时,权重基于相对位置。例如,权重  用于计算 的最终加权平均数,如果adjust=True,则权重分别是  1。如果adjust=False,权重分别是

提取数据

# iloc[] 
>>> print(dataset.iloc[0][0])
19.59000015258789

# iat[] 
>>> print(dataset.iat[0,0])
19.59000015258789

at的使用方法与loc类似,但是比loc有更快的访问数据的速度,而且只能访问单个元素,不能访问多个元素。iatiloc类似。

# loc[]
>>> print(df.loc[0]['High'])
19.65999984741211
# iloc[]
>>> print(df.iloc[0])

Date         2015-12-31 00:00:00
Open                      19.59
High                       19.66
Low                        19.51
Close                      19.62
Adj Close               19.3691
Volume                  382600
ewm                      19.3691
Name: 0, dtype: object

重置索引

>>> df = dataset.reset_index()
>>> df.head()

删除列

# 删除数据
>>> new_df = df.drop(['Date'], axis=1)
>>> new_df.head()

添加列

# 添加日期
>>> new_column = df['Date']
>>> new_df['Date'] = new_column
>>> new_df.head()

移动列

# 将 Date 移动至第一列
>>> cols = list(new_df)
>>> cols.insert(0, cols.pop(cols.index('Date')))
>>> cols
['Date''Open''High''Low''Close''Adj Close''Volume''ewm']

# loc是DataFrame有索引标记的值的
>>> new_df = new_df.loc[:, cols]
>>> new_df.head()

删除列

>>> del new_df['Close']
>>> new_df.head()

重命名列

  • 重命名
>>> new_df = new_df.rename(index=str, 
                           columns={'Adj Close':'Close'})
>>> new_df.head()


  • 列名改为大写
>>> new_df.rename(str.upper, axis='columns')


  • 列名改为小写
# column name to lower case
new_df.rename(str.lower, axis='columns')

选择多个列

>>> new_df[new_df.columns[1:5]]

选择多个行

>>> new_df[1:4]

创建Dataframe

>>> stock_df = pd.DataFrame([[123.50145.35165.50], 
                             [152.35154.67160.35], 
                             [201.25236.54254.69]], 
                            columns=['IBM''Apple''Tesla'])
>>> stock_df

IBMAppleTesla
0123.50145.35165.50
1152.35154.67160.35
2201.25236.54254.69

替换数据

>>> stock_df = stock_df.replace([201.25145.35], [888888])
>>> stock_df
IBMAppleTesla
0123.50888.00165.50
1152.35154.67160.35
2888.00236.54254.69
>>> stock_df = stock_df.replace([165.50160.35], ['NaN''NaN'])
>>> stock_df
IBMAppleTesla
0123.5888NaN
1152.35154.67NaN
2888236.54254.69

获取数据框数据

>>> for index, row in stock_df.iterrows() :
...     print(row['IBM'], row['Apple'])
123.5 888.0
152.35 154.67
888.0 236.54

当然,前面这篇pandas/numpy高效数据处理方法总结里列举了很多实用方法,大家可随时查看。

NumPy

NumPy是专为简化Python中的数组运算而设计的,每个NumPy数组都具有以下属性:

  • ndim:维数。
  • shape:每一维的大小。
  • size:数组中元素的总数。
  • dtype:数组的数据类型(例如int、float、string等)。
# Numpy 模块
>>> import numpy as np

将数据集转换为numpy

# 将打开的DataFrame转换为numpy数组
>>> Open_array = np.array(dataset['Open'])
>>> Open_array  
array([19.59000015, 19.12999916, 19.09000015, ..., 79.44000244,
       79.19000244, 78.56999969])

查看单个元素

>>> print("First element:", Open_array [0])
>>> print("Second element:", Open_array [1])
>>> print("Second last element:", Open_array[-1])
First element: 19.59000015258789
Second element: 19.1299991607666
Second last element: 78.56999969482422

查看多个元素

>>> print(Open_array[2:5]) # 第3个到第5个
[19.09000015 18.63999939 18.04999924]

>>> print(Open_array[:-5]) # 从开始到最后第4个
[19.59000015 19.12999916 19.09000015 ... 80.69999695 81.90000153
 81.65000153]

>>> print(Open_array[5:])  # 第6个到最后
[18.32999992 17.76000023 17.64999962 ... 79.44000244 79.19000244
 78.56999969]

>>> print(Open_array[:])   # 开始到最后
[19.59000015 19.12999916 19.09000015 ... 79.44000244 79.19000244
 78.56999969]

修改元素

  • 改变第一个元素
>>> volume = np.array(dataset['Volume'])

>>> volume[0] = 0    
>>> print(volume)  
[      0  469100  170300 ... 5923100 3468900 1715900]
  • 改变多个元素
# 更改第3到5个元素
>>> volume[2:5] = np.array([468])   
>>> print(volume)      
[      0  469100       4 ... 5923100 3468900 1715900]

增加元素

>>> add_numbers = np.array([123])
>>> np.concatenate((volume, add_numbers)
array([     0, 469100,      4, ...,      1,      2,      3], dtype=int64)
>>> np.append(volume, add_numbers, axis=0)
array([     0, 469100,      4, ...,      1,      2,      3], dtype=int64)

删除元素

  • 直接删除
>>> print(volume)
[    0  469100     4 ... 5923100 3468900 1715900]
>>> np.delete(volume, 1
array([    0,     4,     6, ..., 5923100, 3468900, 1715900], dtype=int64)
  • 转换为list()来使用remove
>>> volume = volume.tolist() # Convert tolist() to use remove
>>> volume
>>> volume.remove(0)
>>> print(volume)
>>> print(volume.pop(2))
>>> print(volume)

Matrix

在数学中,矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合。由 m × n 个数aij排成的m行n列的数表称为m行n列的矩阵,简称m × n矩阵。矩阵运算在科学计算中非常重要,而矩阵的基本运算包括矩阵的加法,减法,数乘,转置,共轭和共轭转置 。

>>> import numpy as np # 对于矩阵和线性代数
>>> import numpy.matlib

报错提示:  
这里用到 Matrix时,需要将含有Matrix的子包matlib导入,不然会报错。module 'numpy' has no attribute 'matlib'

这是因为numpymatlibnumpy的可选子包,必须单独导入。如果您只导入numpy而不导入子包matlib,那么Python将把matlib作为numpy包的属性来查找。如果没有导入numpy.matlib,这个属性没有被分配给numpy

>>> import yfinance as yf
>>> symbol = 'TCEHY'
>>> start = '2021-03-20'
>>> end = '2021-03-31'
>>> yf.pdr_override()
>>> dataset = yf.download(symbol,start,end)
>>> df = dataset.drop(['High''Low''Close''Volume'], axis=1)
>>> df.head()

OpenAdj Close
Date

2021-03-1980.69999782.639999
2021-03-2281.90000282.769997
2021-03-2381.65000280.930000
2021-03-2480.93000076.809998
2021-03-2577.30999877.419998

转换为矩阵

>>> A = np.matrix(df)
>>> A
matrix([[80.69999695, 82.63999939],
       [81.90000153, 82.76999664],
       [81.65000153, 80.93000031],
       [80.93000031, 76.80999756],
       [77.30999756, 77.41999817],
       [79.44000244, 80.98000336],
       [79.19000244, 78.69000244],
       [78.56999969, 78.83000183]])

因为matrix很多操作不方便,如添加修改某个元素。这里可以先用array函数读写完毕以后,再用matrix函数让它恢复矩阵类型。

转换数组

>>> A = np.array(df)
>>> A
array([[80.69999695, 82.63999939],
       [81.90000153, 82.76999664],
       [81.65000153, 80.93000031],
       [80.93000031, 76.80999756],
       [77.30999756, 77.41999817],
       [79.44000244, 80.98000336],
       [79.19000244, 78.69000244],
       [78.56999969, 78.83000183]])

访问元素

>>> type(A)
numpy.ndarray

>>> print("A =", A)
A = [[80.69999695 82.63999939]
 [81.90000153 82.76999664]
 [81.65000153 80.93000031]
 [80.93000031 76.80999756]
 [77.30999756 77.41999817]
 [79.44000244 80.98000336]
 [79.19000244 78.69000244]
 [78.56999969 78.83000183]]


>>> print("A[1] =", A[1])      # 第2行
A[1] = [81.90000153 82.76999664]

>>> print("A[1][2] =", A[1][1])   # 第2行的第2个元素
A[1][2] = 82.7699966430664

>>> print("A[0][-1] =", A[0][-1])  # 第1行的最后第1个元素A[0][-1] = 82.63999938964844

取出元素放到列表中

>>> column = [];        # 空列表
>>> for row in A:
...     column.append(row[1]) 

>>> print("Second column =", column)
Second column = [82.63999938964844, 82.7699966430664, 80.93000030517578, 76.80999755859375,  
                 77.41999816894531, 80.9800033569336,8.69000244140625, 78.83000183105469]

arange and shape


>>> A = np.arange(4)
>>> print('A =', A)
A = [0 1 2 3]
>>> B = np.arange(12).reshape(26)
>>> print('B =', B)
B = [[ 0  1  2  3  4  5]
   
[ 6  7  8  9 10 11]]

矩阵的运算

>>> A = np.array(dataset['High'], dataset['Low'])
>>> B = np.array(dataset['Open'], dataset['Close'])
>>> print(A)
array([82.63999939, 82.84999847, 81.94000244, 81.16000366, 
       78.19000244, 80.98000336, 79.80000305, 79.41000366])

  • 矩阵加法
>>> C = A + B
>>> print("矩阵加法: \n", C)

矩阵加法: 
[163.33999634 164.75     163.59000397 162.09000397 
155.5 160.4200058  158.99000549 157.98000336]

  • 矩阵减法
>>> D = A - B
>>> print("矩阵减法: \n", D)

矩阵减法: 
 [1.94000244 0.94999695 0.29000092 0.23000336 
0.88000488 1.54000092 0.61000061 0.84000397]

  • 两个矩阵的乘法
>>> E = A.dot(B)
>>> print("两矩阵点乘: \n", E)
两矩阵点乘: 
 51749.67010773317

  • 矩阵转置
>>> T = A.transpose()
>>> print("矩阵转置: \n", T)

矩阵转置: 
 [82.63999939 82.84999847 81.94000244 81.16000366 
78.19000244 80.98000336 79.80000305 79.41000366]

访问矩阵元素、行和列

  • 访问一维矩阵单个元素
# 第一个元素 
>>> print("A[0] =", A[0])
A[0] = 82.63999938964844

# 第三个元素
>>> print("A[2] =", A[2])
A[2] = 81.94000244140625

# 最后一个元素 
>>> print("A[-1] =", A[-1])  
A[-1] = 79.41000366210938
  • 访问多维矩阵单个元素
>>> A = np.array(dataset[['Open''Low''High''Close']])
>>> print("矩阵A: \n", A)
矩阵A: 
 [[80.69999695 80.09999847 82.63999939 82.63999939]
 [81.90000153 81.62999725 82.84999847 82.76999664]
 [81.65000153 80.91000366 81.94000244 80.93000031]
 [80.93000031 76.59999847 81.16000366 76.80999756]
 [77.30999756 76.80000305 78.19000244 77.41999817]
 [79.44000244 77.81999969 80.98000336 80.98000336]
 [79.19000244 78.06999969 79.80000305 78.69000244]
 [78.56999969 78.02999878 79.41000366 78.83000183]]


# 第一行的第一个元素
>>> print("A[0][0] =", A[0][0])  
A[0][0] = 80.69999694824219

# 第二行的第三个元素
>>> print("A[1][2] =", A[1][2])
A[1][2] = 82.8499984741211

# 最后一行的最后一个元素
>>> print("A[-1][-1] =", A[-1][-1])
A[-1][-1] = 78.83000183105469
  • 访问矩阵的行
 # 第一行
>>> print("A[0] =", A[0])
A[0] = [80.69999695 80.09999847 82.63999939 82.63999939]

# 第三行
>>> print("A[2] =", A[2]) 
A[2] = [81.65000153 80.91000366 81.94000244 80.93000031]

# 最后一行
>>> print("A[-1] =", A[-1]) 
A[-1] = [78.56999969 78.02999878 79.41000366 78.83000183]
  • 访问矩阵的列
 # 第一列
>>> print("A[:,0] =",A[:,0])
A[:,0] = [80.69999695 81.90000153 81.65000153 80.93000031 77.30999756 79.44000244 79.19000244 78.56999969]

# 第四列
>>> print("A[:,3] =", A[:,3]) 
A[:,3] = [82.63999939 82.76999664 80.93000031 76.80999756 77.41999817 80.98000336 78.69000244 78.83000183]

# 最后一列
>>> print("A[:,-1] =", A[:,-1]) 
A[:,-1] = [82.63999939 82.76999664 80.93000031 76.80999756 77.41999817 80.98000336 78.69000244 78.83000183]
  • 访问多维矩阵多个元素
# 没有逗号相隔,默认获取行
# 第3到第5个元素
>>> print(A[2:5])    
[[81.65000153 80.91000366 81.94000244 80.93000031]
 [80.93000031 76.59999847 81.16000366 76.80999756]
 [77.30999756 76.80000305 78.19000244 77.41999817]]


# 第1到第3个元素
>>> print(A[:-5])
[[80.69999695 80.09999847 82.63999939 82.63999939]
 [81.90000153 81.62999725 82.84999847 82.76999664]
 [81.65000153 80.91000366 81.94000244 80.93000031]]


# 第6行到最后一个元素
>>> print(A[5:])  
[[79.44000244 77.81999969 80.98000336 80.98000336]
 [79.19000244 78.06999969 79.80000305 78.69000244]
 [78.56999969 78.02999878 79.41000366 78.83000183]]


# 第1个到最后一个元素
>>> print(A[:]) 

[[80.69999695 80.09999847 82.63999939 82.63999939]
 [81.90000153 81.62999725 82.84999847 82.76999664]
 [81.65000153 80.91000366 81.94000244 80.93000031]
 [80.93000031 76.59999847 81.16000366 76.80999756]
 [77.30999756 76.80000305 78.19000244 77.41999817]
 [79.44000244 77.81999969 80.98000336 80.98000336]
 [79.19000244 78.06999969 79.80000305 78.69000244]
 [78.56999969 78.02999878 79.41000366 78.83000183]]


# 反转一个列表
>>> print(A[::-1]) 
[[78.56999969 78.02999878 79.41000366 78.83000183]
 [79.19000244 78.06999969 79.80000305 78.69000244]
 [79.44000244 77.81999969 80.98000336 80.98000336]
 [77.30999756 76.80000305 78.19000244 77.41999817]
 [80.93000031 76.59999847 81.16000366 76.80999756]
 [81.65000153 80.91000366 81.94000244 80.93000031]
 [81.90000153 81.62999725 82.84999847 82.76999664]
 [80.69999695 80.09999847 82.63999939 82.63999939]]


# 前2行,前4列
>>> print(A[:2, :4]) 
[[80.69999695 80.09999847 82.63999939 82.63999939]
 [81.90000153 81.62999725 82.84999847 82.76999664]]


# 前1行,所有列
>>> print(A[:1,])  
[[80.69999695 80.09999847 82.63999939 82.63999939]]

# 所有行,第3列
>>> print(A[:,2])  
[82.63999939 82.84999847 81.94000244 81.16000366 78.19000244 80.98000336 79.80000305 79.41000366]

# 所有行,第3到5列
>>> print(A[:, 2:5])  # 共4列,只能取到第3和第4列
[[82.63999939 82.63999939]
 [82.84999847 82.76999664]
 [81.94000244 80.93000031]
 [81.16000366 76.80999756]
 [78.19000244 77.41999817]
 [80.98000336 80.98000336]
 [79.80000305 78.69000244]
 [79.41000366 78.83000183]]


- EOF -

推荐阅读  点击标题可跳转

1、面试必备 :10道海量数据处理,你会几道?

2、数据仓库建设灵魂 10 问

3、百亿数据,毫秒级返回,如何构建?


看完本文有收获?请转发分享给更多人

关注「大数据与机器学习文摘」,成为Top 1%

点赞和在看就是最大的支持❤️

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存