掌握 NumPy 常用函数 II

作者: 布客飞龙 | 来源:发表于2017-06-11 16:58 被阅读77次

    掌握 NumPy 常用函数 II

    斐波那契数的第 n 项

    # 来源:NumPy Cookbook 2e Ch3.1
    
    import numpy as np
    
    # 斐波那契数列的每个新项都由之前的两项相加而成
    # 以 1 和 2 开始,前 10 项为:
    # 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
    
    # 斐波那契数列的通项公式为:
    # fn = (phi ** n - (-phi) ** (-n)) / 5 ** 0.5
    # 其中 phi 是黄金比例,phi = (1 + 5 ** 0.5) / 2
    
    # 考虑一个斐波那契数列,每一项的值不超过四百万
    # 求出值为偶数的项的和
    
    # 1. 计算 phi
    phi = (1 + np.sqrt(5))/2 
    print("Phi", phi)
    # Phi 1.61803398875
    
    # 2. 寻找小于四百万的项的索引
    n = np.log(4 * 10 ** 6 * np.sqrt(5) + 0.5)/np.log(phi) 
    print(n)
    # 33.2629480359
    
    # 3. 创建 1 ~ n 的数组
    n = np.arange(1, n) 
    print(n)
    
    # 4. 计算斐波那契数
    fib = (phi**n - (-1/phi)**n)/np.sqrt(5) 
    print("First 9 Fibonacci Numbers", fib[:9])
    # First 9 Fibonacci Numbers [  1.   1.   2.   3.   5.   8.  13.  21.  34.] 
    
    # 5. 转换为整数(可选)
    fib = fib.astype(int) 
    print("Integers", fib)
    '''
    Integers [      1       1       2       3       5       8      13      21      34
      ... snip ... snip ...
      317811  514229  832040 1346269 2178309 3524578] 
    '''
    
    # 6. 选择值为偶数的项
    eventerms = fib[fib % 2 == 0] 
    print(eventerms)
    # [      2       8      34     144     610    2584   10946   46368  196418  832040 3524578]
    
    # 7. 求和
    print(eventerms.sum())
    # 4613732
    

    寻找质因数

    # 来源:NumPy Cookbook 2e Ch3.2
    
    from __future__ import print_function 
    import numpy as np
    
    # 13195 的质因数是 5, 7, 13 和 29
    # 600851475143 的最大质因数是多少呢?
    
    N = 600851475143 
    LIM = 10 ** 6
    
    
    def factor(n): 
        # 1. 创建搜索范围的数组
        # a 是 sqrtn ~ sqrtn + lim - 1 的数组
        # 其中 sqrtn 是 n 平方根向上取整
        # lim 是 sqrtn 和 10e6 的较小值
        a = np.ceil(np.sqrt(n))   
        lim = min(n, LIM)   
        a = np.arange(a, a + lim)   
        b2 = a ** 2 - n
        
        # 2. 检查 b 是否是平方数
        # modf 用于取小数部分
        fractions = np.modf(np.sqrt(b2))[0]
        
        # 3. 寻找没有小数部分的地方
        # 这里的 b 为平方数
        # where 用于把布尔索引变成位置索引
        # 但是效果是一样的
        indices = np.where(fractions == 0)
        
        # 4. 寻找 b 为平方数时,a 的值,并取出第一个
        a = np.ravel(np.take(a, indices))[0]
        # 或者 a = a[indices][0]
        
        # 求出 c 和 d
        a = int(a)   
        b = np.sqrt(a ** 2 - n)    
        b = int(b)   
        c = a + b   
        d = a - b
        
        # 到达终止条件则返回
        if c == 1 or d == 1:      
            return
        
        # 打印当前 c 和 d 并递归
        print(c, d)   
        factor(c)   
        factor(d)
    
    factor(N)
    '''
    1234169 486847 
    1471 839 
    6857 71
    '''
    

    寻找回文数

    # 来源:NumPy Cookbook 2e Ch3.3
    
    # 回文数正着读还是反着读都一样
    # 由两个两位数的乘积构成的最大回文数是 9009 = 91 x 99
    # 寻找两个三位数乘积构成的最大回文数
    
    # 1. 创建三位数的数组
    a = np.arange(100, 1000) 
    np.testing.assert_equal(100, a[0]) np.testing.assert_equal(999, a[-1])
    
    # 2. 创建两个数组中元素的乘积
    # outer 计算数组的外积,也就是 a[i] x a[j] 的矩阵
    # ravel 将其展开之后,就是每个元素乘积的数组了
    numbers = np.outer(a, a) 
    numbers = np.ravel(numbers) 
    numbers.sort() 
    np.testing.assert_equal(810000, len(numbers)) 
    np.testing.assert_equal(10000, numbers[0]) 
    np.testing.assert_equal(998001, numbers[-1])
    
    #3. 寻找最大的回文数
    for number in numbers[::-1]:   
        s = str(numbers[i])
        if s == s[::-1]:
            print(s)     
            break
    

    稳态向量

    # 来源:NumPy Cookbook 2e Ch3.4
    # 稳态向量:状态转移矩阵中
    # 特征值 1 对应的向量,满足 Ax = x
    
    from __future__ import print_function 
    from matplotlib.finance import quotes_historical_yahoo 
    from datetime import date 
    import numpy as np
    
    # 获取 'AAPL' 股票近一年的收盘价
    # quotes 是元组的列表,元组是每天的数据
    # 结构为 [日期, 开盘价, 最高价, 最低价, 收盘价, 成交量]
    today = date.today()
    start = (today.year - 1, today.month, today.day)
    quotes = quotes_historical_yahoo('AAPL', start, today) 
    close =  [q[4] for q in quotes]
    
    # 计算收盘价的状态,和前一天相比,上涨、下跌还是持平
    # diff 求出相邻两项的差
    # sign 取每个元素的符号
    states = np.sign(np.diff(close))
    
    # 创建状态转移矩阵
    # SM[i, j] 表示 signs[i] 向 signs[j] 转移的概率
    NDIM = 3 
    SM = np.zeros((NDIM, NDIM))
    
    # 状态列表为 [下跌, 持平, 上涨]
    signs = [-1, 0, 1] 
    k = 1
    
    for i, signi in enumerate(signs):
        # 对于每一个 signi
        # 获取起始状态为 signi 的位置
        start_indices = np.where(states[:-1] == signi)[0] 
        
        # 求出 signi 的出现次数
        # 并加上一个常数用于去掉 0
        N = len(start_indices) + k * NDIM
        
        # 跳过出现次数为 0 的情况
        if N == 0:
            continue
    
        # 获取对应的结束状态
        end_values = states[start_indices + 1]
        
        for j, signj in enumerate(signs):
            # 对于每一个 signj
            # 获取起始状态为 signi 时,结束状态为 signj 的数量
            occurrences = len(end_values[end_values == signj])
            # 除以 signi 的出现次数就是概率
            SM[i][j] = (occurrences + k)/float(N)
    
    print(SM)
    '''
    [[ 0.5047619   0.00952381  0.48571429] 
     [ 0.33333333  0.33333333  0.33333333] 
     [ 0.33774834  0.00662252  0.65562914]] 
    '''
    
    # 计算 SM 的特征值和特征向量
    eig_out = np.linalg.eig(SM) 
    print(eig_out)
    '''
    (array([ 1.        ,  0.16709381,  0.32663057]), 
     array([[  5.77350269e-01,   7.31108409e-01,   7.90138877e-04],       
            [  5.77350269e-01,  -4.65117036e-01,  -9.99813147e-01],       
            [  5.77350269e-01,  -4.99145907e-01,   1.93144030e-02]])) 
    '''
    
    # 计算特征值 1 的下标
    idx_vec = np.where(np.abs(eig_out[0] - 1) < 0.1) 
    print("Index eigenvalue 1", idx_vec)
    # Index eigenvalue 1 (array([0]),) 
    
    # 特征值 1 对应的特征向量
    x = eig_out[1][:,idx_vec].flatten()
    print("Steady state vector", x) 
    # Steady state vector [ 0.57735027  0.57735027  0.57735027]
    print("Check", np.dot(SM, x))
    # Check [ 0.57735027  0.57735027  0.57735027]
    

    探索幂率

    # 来源:NumPy Cookbook 2e Ch3.5
    # 幂律就是 y = c * x ** k 的函数关系
    
    from matplotlib.finance import quotes_historical_yahoo 
    from datetime import date 
    import numpy as np 
    import matplotlib.pyplot as plt
    
    # 1. 获取收盘价
    today = date.today() 
    start = (today.year - 1, today.month, today.day)
    quotes = quotes_historical_yahoo('IBM', start, today) 
    close =  np.array([q[4] for q in quotes])
    
    # 2. 获取正的对数收益 
    logreturns = np.diff(np.log(close)) 
    pos = logreturns[logreturns > 0]
    
    # 3. 获取收益频率
    # histogram 默认将输入数据分为 10 个组
    # 返回一个元组,第一项是每个组的频数
    # 第二项是每个组的范围
    counts, rets = np.histogram(pos) 
    # 取每个组的中间值
    rets = rets[:-1] + (rets[1] - rets[0])/2 
    
    # 计算频数非 0 的位置
    indices0 = np.where(counts != 0) 
    # 过滤掉频数为 0 的数据点
    counts = np.take(counts, indices0)[0] 
    rets = np.take(rets, indices0)[0] 
    # 计算对数周期
    freqs = 1.0/counts 
    freqs =  np.log(freqs)
    
    # 4. 将周期和收益拟合为直线
    p = np.polyfit(rets,freqs, 1)
    
    # 5. 绘制结果
    plt.title('Power Law') 
    plt.plot(rets, freqs, 'o', label='Data') 
    plt.plot(rets, p[0] * rets + p[1], label='Fit') 
    plt.xlabel('Log Returns') 
    plt.ylabel('Log Frequencies') 
    plt.legend() 
    plt.grid() 
    plt.show()
    
    # log(T) = k * log(R) + c
    # T = exp(c) * R ** k
    # 满足幂率关系
    

    收益的分布

    # 来源:NumPy Cookbook 2e Ch3.6
    from __future__ import print_function 
    from matplotlib.finance 
    import quotes_historical_yahoo 
    from datetime import date 
    import numpy as np 
    import scipy.stats 
    import matplotlib.pyplot as plt
    
    #1. 获取 AAPL 一年内的收盘价
    today = date.today() 
    start = (today.year - 1, today.month, today.day)
    
    quotes = quotes_historical_yahoo('AAPL', start, today) 
    close =  np.array([q[4] for q in quotes])
    
    #2. 计算对数收益
    logreturns = np.diff(np.log(close))
    
    #3. 计算 breakout 和 pullback
    # 我们每 50 天交易一次,所以频率是 0.02
    # 我们的策略是低于一定百分比时买入
    # 高于一定百分比时卖出
    # scoreatpercentile 寻找百分位点
    freq = 0.02 
    breakout = scipy.stats.scoreatpercentile(logreturns, 100 * (1 - freq) ) 
    pullback = scipy.stats.scoreatpercentile(logreturns, 100 * freq)
    
    #4. 生成买入和卖出
    # compress(idx, arr) 相当于 arr[idx]
    buys = np.compress(logreturns < pullback, close) 
    sells = np.compress(logreturns > breakout, close) 
    print(buys) 
    # [  77.76375466   76.69249773  102.72        101.2          98.57      ] 
    print(sells) 
    # [ 74.95502967  76.55980292  74.13759123  80.93512599  98.22      ] 
    print(len(buys), len(sells)) 
    # 5 5 
    print(sells.sum() - buys.sum())
    # -52.1387025726 
    
    #5. 绘制对数收益的直方图
    # 直接传入数据调用 hist 就可以
    # 横轴是收益值,纵轴是频数
    plt.title('Periodic Trading') 
    plt.hist(logreturns) 
    plt.grid() 
    plt.xlabel('Log Returns') 
    plt.ylabel('Counts') 
    plt.show() 
    

    模拟随机交易

    # 来源:NumPy Cookbook 2e Ch3.7
    from __future__ import print_function 
    from matplotlib.finance import quotes_historical_yahoo 
    from datetime import date 
    import numpy as np 
    import matplotlib.pyplot as plt
    
    def get_indices(high, size):
        #2. 获取 size 个 0 ~ high 之间的随机整数
        return np.random.randint(0, high, size)
    
    #1. 获取 AAPL 一年的收盘价
    today = date.today() 
    start = (today.year - 1, today.month, today.day)
    quotes = quotes_historical_yahoo('AAPL', start, today) 
    close =  np.array([q[4] for q in quotes])
    
    # 模拟 2000 次
    # 每次模拟中,买入 5 次,卖出 5 次
    nbuys = 5 
    N = 2000 
    profits = np.zeros(N)
    
    for i in xrange(N):   
        #3. 模拟交易
        # np.take(arr, idx) 相当于 arr[idx]
        buys = np.take(close, get_indices(len(close), nbuys))   
        sells = np.take(close, get_indices(len(close), nbuys))   
        profits[i] = sells.sum() - buys.sum()
    
    print("Mean", profits.mean()) 
    print("Std", profits.std())
    
    #4. 绘制利润的直方图 
    plt.title('Simulation') 
    plt.hist(profits) 
    plt.xlabel('Profits') 
    plt.ylabel('Counts') 
    plt.grid() 
    plt.show() 
    

    埃拉托色尼筛选法

    # 来源:NumPy Cookbook 2e Ch3.8
    # 埃拉托色尼筛选法是筛选质数的算法
    # 它迭代地判断倍数来寻找质数
    # 根据定义,倍数不是质数,可以忽略
    from __future__ import print_function 
    import numpy as np
    
    LIM = 10 ** 6 
    N = 10 ** 9 
    P = 10001 
    primes = [] 
    p = 2
    
    # 前六个质数为 2, 3, 5, 7, 11, 13,第六个是 13
    # 那么第 10001 个呢?
    def sieve_primes(a, p):
        #2. 过滤掉 p 的倍数   
        a = a[a % p != 0]
        return a
    
    #1. 原理是创建以 3 开始的连续奇数数组
    # (因为除了 2 的偶数都是合数)
    # 每次取第一个元素,并过滤掉它的倍数
    # 就能够得到质数数组
    for i in xrange(3, N, LIM):
        a = np.arange(i, i + LIM, 2)
        
        while len(primes) < P:  
            a = sieve_primes(a, p)
            primes.append(p)
            p = a[0]
    
    print(len(primes), primes[P-1])
    

    相关文章

      网友评论

        本文标题:掌握 NumPy 常用函数 II

        本文链接:https://www.haomeiwen.com/subject/slghqxtx.html