{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "##内容索引\n", "1. 计算股票收益率----\n", "diff做差分、std求标准差、where函数返回满足条件的数组索引\n", "\n", "2. 日期分析例子----\n", "载入文件对日期的处理、where和take函数、argmax和argmin函数\n", "\n", "3. 周汇总例子----\n", "apply_along_axis函数会调用一个自定义函数,作用于每一个数组元素上\n", "\n", "4. 线性模型预测价格----\n", "linalg.lstsq函数\n", "\n", "5. 绘制趋势线例子----\n", "\n", "6. ndarray补充----\n", "clip函数,修剪;\n", "compress函数,压缩;\n", "prod函数,相乘;\n", "cumprod函数,累积乘积。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "上一小节,介绍了numpy中读取数据,计算均值方差,最大最小值等基本操作。这一节中,我将继续学习numpy常用函数,用来做更加深入的股票分析。\n", "这里股票分析只是一个例子,不必在意概念细节,只是针对现有的数据来熟悉numpy的操作。" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##1. 股票收益率" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "简单收益率是指相邻两个价格之间的变化率,而对数收益率是指所有价格取对数后两两之间的差值。由于对数收益率是两两价格相除再去对数,所以其**可以用来衡量价格收益率。**\n", "\n", "投资者最感兴趣的是收益率的方差或标准差,这代表了投资风险的大小。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "###1.1 计算简单收益率\n", "diff函数计算离散差分,计算收益率,需要用差值除以前一天的价格。" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": true }, "outputs": [], "source": [ "#cp means closing price\n", "cp = np.loadtxt('data.csv', delimiter=',', usecols=(6,), unpack=True)\n", "cp_diff = np.diff(cp)\n", "rate_of_returns = cp_diff / cp[:-1]" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 336.1 , 339.32, 345.03, 344.32, 343.44, 346.5 , 351.88,\n", " 355.2 , 358.16, 354.54, 356.85, 359.18, 359.9 , 363.13,\n", " 358.3 , 350.56, 338.61, 342.62, 342.88, 348.16, 353.21,\n", " 349.31, 352.12, 359.56, 360. , 355.36, 355.76, 352.47,\n", " 346.67, 351.99])" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cp" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 336.1 , 339.32, 345.03, 344.32, 343.44, 346.5 , 351.88,\n", " 355.2 , 358.16, 354.54, 356.85, 359.18, 359.9 , 363.13,\n", " 358.3 , 350.56, 338.61, 342.62, 342.88, 348.16, 353.21,\n", " 349.31, 352.12, 359.56, 360. , 355.36, 355.76, 352.47,\n", " 346.67])" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#去掉最后一个\n", "#从开始到倒数第二个\n", "cp[:-1]" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 0.00958048, 0.01682777, -0.00205779, -0.00255576, 0.00890985,\n", " 0.0155267 , 0.00943503, 0.00833333, -0.01010721, 0.00651548,\n", " 0.00652935, 0.00200457, 0.00897472, -0.01330102, -0.02160201,\n", " -0.03408832, 0.01184253, 0.00075886, 0.01539897, 0.01450483,\n", " -0.01104159, 0.00804443, 0.02112916, 0.00122372, -0.01288889,\n", " 0.00112562, -0.00924781, -0.0164553 , 0.01534601])" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rate_of_returns" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "standard deviation = 0.0129221344368\n" ] } ], "source": [ "print \"standard deviation = \", np.std(rate_of_returns)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "###1.2 对数收益率" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "取对数要注意事先检查数据中不包含0和负值,确保输入满足定义域条件" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": true }, "outputs": [], "source": [ "log_rate_of_returns = np.diff(np.log(cp))" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 0.00953488, 0.01668775, -0.00205991, -0.00255903, 0.00887039,\n", " 0.01540739, 0.0093908 , 0.0082988 , -0.01015864, 0.00649435,\n", " 0.00650813, 0.00200256, 0.00893468, -0.01339027, -0.02183875,\n", " -0.03468287, 0.01177296, 0.00075857, 0.01528161, 0.01440064,\n", " -0.011103 , 0.00801225, 0.02090904, 0.00122297, -0.01297267,\n", " 0.00112499, -0.00929083, -0.01659219, 0.01522945])" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "log_rate_of_returns" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "得到收益率为正的情况,where函数可以根据制定条件返回数组的索引值" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Indices with positive returns (array([ 0, 1, 4, 5, 6, 7, 9, 10, 11, 12, 16, 17, 18, 19, 21, 22, 23,\n", " 25, 28]),)\n" ] } ], "source": [ "pos_return_indices = np.where(log_rate_of_returns > 0)\n", "print 'Indices with positive returns', pos_return_indices" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "###1.3 计算波动率\n", "波动率volatility是对价格变动的一种度量。**年波动率等于对数收益率的标准差除以其均值,在除以交易日倒数的平方根,通常交易日去252天。**" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "129.274789911\n" ] } ], "source": [ "annual_volatility = np.std(log_rate_of_returns) / np.mean(log_rate_of_returns)\n", "annual_volatility = annual_volatility / np.sqrt(1. / 252.)\n", "print annual_volatility" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "sqrt函数中的除法运算必须使用浮点数才能得到正确结果。" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Monthly volatility 37.3184173773\n" ] } ], "source": [ "print \"Monthly volatility\", annual_volatility * np.sqrt(1. / 12.)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##2. 日期分析\n", "我们读入收盘价数据,根据星期几来切分数据,计算平均价格,最后找出一周的那一天的平均收盘价最高" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Numpy是面向浮点数运算的,对日期处理需要专门的方法**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "loadtxt函数中有一个特定的参数converters,这是数据列到转换函数之间映射的字典。" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": true }, "outputs": [], "source": [ "#convert funtion\n", "import datetime\n", "def datestr2num(s):\n", " return datetime.datetime.strptime(s, \"%d-%m-%Y\").date().weekday()\n", "\n", "#字符串首先会按照指定形式\"%d-%m-%Y\"转换成一个datetime对象,随后datetime对象被转换成date对象,最后调用weekday方法返回一个数字\n", "#0代表星期一,6代表星期天" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Dates = [ 4. 0. 1. 2. 3. 4. 0. 1. 2. 3. 4. 0. 1. 2. 3. 4. 1. 2.\n", " 3. 4. 0. 1. 2. 3. 4. 0. 1. 2. 3. 4.]\n" ] } ], "source": [ "#cp means closing price\n", "dates, cp = np.loadtxt('data.csv', delimiter=',', usecols=(1,6), converters={1:datestr2num}, unpack=True)\n", "print \"Dates = \", dates" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": true }, "outputs": [], "source": [ "#保存各工作日的平均收盘价\n", "averages = np.zeros(5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**where函数会根据指定的条件返回所有满足条件的数组元素的索引值;take函数根据这些索引值从数组中取出相应的元素。**" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Day 0 prices [[ 339.32 351.88 359.18 353.21 355.36]] Average 351.79\n", "Day 1 prices [[ 345.03 355.2 359.9 338.61 349.31 355.76]] Average 350.635\n", "Day 2 prices [[ 344.32 358.16 363.13 342.62 352.12 352.47]] Average 352.136666667\n", "Day 3 prices [[ 343.44 354.54 358.3 342.88 359.56 346.67]] Average 350.898333333\n", "Day 4 prices [[ 336.1 346.5 356.85 350.56 348.16 360. 351.99]] Average 350.022857143\n" ] } ], "source": [ "for i in xrange(5):\n", " indices = np.where(dates == i)\n", " prices = np.take(cp, indices)\n", " avg = prices.mean()\n", " print \"Day\", i, \"prices\", prices, \"Average\", avg\n", " averages[i] = avg" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Highest average 352.136666667\n", "Top day of the week 2\n", "Lowest average 350.022857143\n", "Bottom day of the week 4\n" ] } ], "source": [ "#找出哪个工作日的平均收盘价最高,哪个最低\n", "top = averages.max()\n", "bottom = averages.min()\n", "print \"Highest average\", top\n", "print \"Top day of the week\", np.argmax(averages)\n", "print \"Lowest average\", bottom\n", "print \"Bottom day of the week\", np.argmin(averages)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**argmin函数返回的是averages数组中最小元素的索引值,argmax同理**" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "##3. 周汇总" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The first Monday index is 1\n" ] } ], "source": [ "dates, op, hp, lp, cp = np.loadtxt('data.csv', delimiter=',', usecols=(1,3,4,5,6), converters={1: datestr2num}, unpack=True)\n", "cp = cp[:16]\n", "dates = dates[:16]\n", "#找到第一个星期一\n", "first_monday = np.ravel(np.where(dates == 0))[0]\n", "print \"The first Monday index is \",first_monday" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The last Friday index is 15\n" ] } ], "source": [ "#找到最后一个周五\n", "last_friday = np.ravel(np.where(dates == 4))[-1]\n", "print \"The last Friday index is \", last_friday" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Weeks indices initial [ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]\n" ] } ], "source": [ "#存储三周每一天的索引值\n", "weeks_indices = np.arange(first_monday, last_friday+1)\n", "print \"Weeks indices initial \",weeks_indices" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Weeks indices after split [array([1, 2, 3, 4, 5]), array([ 6, 7, 8, 9, 10]), array([11, 12, 13, 14, 15])]\n" ] } ], "source": [ "#切分数组,每5个元素一个子数组\n", "weeks_indices = np.split(weeks_indices, 3)\n", "print \"Weeks indices after split \", weeks_indices" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**apply_along_axis函数会调用一个自定义函数,作用于每一个数组元素上。**在调用apply_along_axis时提供我们自定义的函数summarize,并指定要作用的轴或维度的编号以及函数的参数" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "collapsed": true }, "outputs": [], "source": [ "#这里indices是三个array\n", "def summarize(indices, open, high, low, close):\n", " monday_open = open[indices[0]]\n", " week_high = np.max(np.take(high, indices))\n", " week_low = np.min(np.take(low, indices))\n", " friday_close = close[indices[-1]]\n", " return (\"APPL\", monday_open, week_high, week_low, friday_close)" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Week summary [['APPL' '335.8' '346.7' '334.3' '346.5']\n", " ['APPL' '347.8' '360.0' '347.6' '356.8']\n", " ['APPL' '356.7' '364.9' '349.5' '350.5']]\n" ] } ], "source": [ "#这里参数1,代表作用于每一行,一共三行,得到三行结果\n", "#相当于axis为1的时候进行计算\n", "week_summary = np.apply_along_axis(summarize, 1, weeks_indices, op, hp, lp, cp)\n", "print \"Week summary\", week_summary" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "##4. 用线性模型预测价格\n", "NumPy的linalg包是专门用于线性代数计算的,我们可以根据N个之前的价格利用线性模型进行预测计算。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " 我们假设,一个股价可以用之前股价的线性组合表示出来,即,这个股价等于之前股价的加权和的结果。用线性代数的角度,这是解一个最小二乘法的问题。" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 355.36 355.76 352.47 346.67 351.99]\n", "[ 351.99 346.67 352.47 355.76 355.36]\n" ] } ], "source": [ "#1. 获得N个股价的向量b\n", "cp = np.loadtxt('data.csv', delimiter=',', usecols=(6,), unpack=True)\n", "N = 5\n", "#从倒数第N个数据取到最后\n", "b = cp[-N:]\n", "print b\n", "#翻转数组,越前面数据,日期越新\n", "b = b[::-1]\n", "print b" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Zeros N by N\n", "[[ 0. 0. 0. 0. 0.]\n", " [ 0. 0. 0. 0. 0.]\n", " [ 0. 0. 0. 0. 0.]\n", " [ 0. 0. 0. 0. 0.]\n", " [ 0. 0. 0. 0. 0.]]\n" ] } ], "source": [ "#2. 初始N*N的二维数组A\n", "A = np.zeros((N,N), float)\n", "print \"Zeros N by N\\n\", A" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "A:\n", "[[ 360. 355.36 355.76 352.47 346.67]\n", " [ 359.56 360. 355.36 355.76 352.47]\n", " [ 352.12 359.56 360. 355.36 355.76]\n", " [ 349.31 352.12 359.56 360. 355.36]\n", " [ 353.21 349.31 352.12 359.56 360. ]]\n" ] } ], "source": [ "#3. 用b向量的N个股价值填充数组A\n", "for i in range(N):\n", " A[i,] = cp[-N-1-i : -1-i]\n", " \n", "print \"A:\\n\", A" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x:\n", "[ 0.78111069 -1.44411737 1.63563225 -0.89905126 0.92009049]\n", "residuals:\n", "[]\n", "rank:\n", "5\n", "s:\n", "[ 1.77736601e+03 1.49622969e+01 8.75528492e+00 5.15099261e+00\n", " 1.75199608e+00]\n" ] } ], "source": [ "#4. 使用linalg中的lstsq来解决最小平方和的问题\n", "(x, residuals, rank, s) = np.linalg.lstsq(A, b)\n", "print 'x:\\n', x\n", "print 'residuals:\\n', residuals\n", "print 'rank:\\n', rank\n", "print 's:\\n', s" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**返回的元组中包含稍后要用到的系数向量x,一个残差数组,A的秩以及A的奇异值**" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "357.939161015\n" ] } ], "source": [ "#5. 使用numpy中的dot函数计算系数向量与最近N个价格构成的向量的点积\n", "print np.dot(b, x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##5. 绘制趋势线\n", "趋势线,是根据股价走势图上很多所谓的枢轴点绘成的曲线,即描绘的是价格变化的趋势。" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "collapsed": true }, "outputs": [], "source": [ "%matplotlib inline\n", "from matplotlib.pyplot import plot\n", "from matplotlib.pyplot import show" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Pivots:\n", "[ 338.01 337.88666667 343.88666667 344.37333333 342.07666667\n", " 345.57 350.92333333 354.29 357.34333333 354.18\n", " 356.06333333 358.45666667 359.14 362.84333333 358.36333333\n", " 353.19333333 340.57666667 341.95666667 342.13333333 347.13\n", " 353.12666667 350.90333333 351.62333333 358.42333333 359.34666667\n", " 356.11333333 355.13666667 352.61 347.11333333 349.77 ]\n" ] } ], "source": [ "#我们假设枢轴点的位置是最高价、最低价、收盘价的均值\n", "hp, lp, cp = np.loadtxt('data.csv', delimiter=',', usecols=(4,5,6), unpack=True)\n", "pivots = (hp+lp+cp) / 3\n", "print \"Pivots:\\n\", pivots" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "从枢轴点出发,我们可以推导出阻力位和支撑位。\n", "> 阻力位是指股价上升时遇到阻力,在转秩前的最高价格\n", "\n", "> 支撑位是股价下跌时遇到支撑,在反弹前的最低价格\n", "\n", "他们都是估计量,根据这些估计量,我们可以绘制阻力位和支撑位的趋势线。" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "collapsed": true }, "outputs": [], "source": [ "#定义直线方程为y = Ax,其中A=[t 1],x=[a b]\n", "#展开就是y = at + b\n", "def fit_line(t, y):\n", " #vstack垂直组合\n", " A = np.vstack([t, np.ones_like(t)]).T\n", " return np.linalg.lstsq(A, y)[0]" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "collapsed": false }, "outputs": [], "source": [ "#假设支撑位在枢轴点下方的位置\n", "#阻力点在枢轴点上方的一个位置\n", "t = np.arange(len(cp))\n", "sa, sb = fit_line(t, pivots-(hp-lp))\n", "ra, rb = fit_line(t, pivots+(hp-lp))\n", "support = sa*t + sb\n", "resistance = ra*t + rb" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Conditions:\n", "[False False True True True True True False False True False False\n", " False False False True False False False True True True True False\n", " False True True True False True]\n", "(array([ 2, 3, 4, 5, 6, 9, 15, 19, 20, 21, 22, 25, 26, 27, 29]),)\n", "[ 2 3 4 5 6 9 15 19 20 21 22 25 26 27 29]\n" ] } ], "source": [ "#设置一个判断数据点是否在趋势线之间的条件\n", "condition = (cp > support) & (cp < resistance)\n", "print \"Conditions:\\n\", condition\n", "between_bands = np.where(condition)\n", "print between_bands\n", "print np.ravel(between_bands)" ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 341.92421382 342.19081893 342.45742405 342.72402917 342.99063429\n", " 343.79044964 345.39008034 346.4565008 346.72310592 346.98971104\n", " 347.25631615 348.0561315 348.32273662 348.58934174 349.12255197]\n", "[ 345.03 344.32 343.44 346.5 351.88 354.54 350.56 348.16 353.21\n", " 349.31 352.12 355.36 355.76 352.47 351.99]\n", "[ 352.61688271 352.90732765 353.19777259 353.48821753 353.77866246\n", " 354.64999728 356.39266691 357.55444667 357.84489161 358.13533655\n", " 358.42578149 359.2971163 359.58756124 359.87800618 360.45889606]\n" ] } ], "source": [ "#复查取值\n", "print support[between_bands]\n", "print cp[between_bands]\n", "print resistance[between_bands]" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n1K8AAAAASUVORK5CYII=\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plot(t, cp)\n", "plot(t, support)\n", "plot(t, resistance)" ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number points between bands: 15\n", "Ratio between bands: 0.5\n" ] } ], "source": [ "n_betweens_band = len(np.ravel(between_bands))\n", "print \"Number points between bands: \", n_betweens_band\n", "print \"Ratio between bands: \", float(n_betweens_band)/len(cp)" ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number of points between band2 2nd approach: 15\n" ] } ], "source": [ "#提供另外一种计算支撑位和阻力位之间数据点个数的方法\n", "# []操作符定义选择条件\n", "# intersect1d计算两者相交的结果\n", "a1 = cp[cp > support]\n", "a2 = cp[cp < resistance]\n", "print \"Number of points between band2 2nd approach: \", len(np.intersect1d(a1, a2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##补充: ndarray对象的几种方法\n", "> clip,修剪\n", "\n", "> compress,压缩\n", "\n", "> prod,相乘\n", "\n", "> cumprod,累积乘积" ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a = [0 1 2 3 4]\n", "Clipped: [1 1 2 3 3]\n" ] } ], "source": [ "#clip方法\n", "#将所有比给定最大值还大的元素全部设为给定最大值\n", "#将所有比给定最小值还小的元素全部设为最小值\n", "a = np.arange(5)\n", "print \"a = \",a\n", "print \"Clipped:\", a.clip(1,3)" ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0 1 2 3 4]\n", "Compressed: [3 4]\n" ] } ], "source": [ "#compress方法\n", "#返回一个根据给定条件筛选后的数组\n", "a = np.arange(5)\n", "print a\n", "print \"Compressed: \", a.compress(a > 2)" ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "b = [1 2 3 4 5]\n", "factorial: 120\n" ] } ], "source": [ "# prod方法计算数组中所有元素的乘积\n", "# 这种方法可以计算阶乘 factorial\n", "b = np.arange(1,6)\n", "print \"b = \", b\n", "print \"factorial: \", b.prod()" ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "factorials array: [ 1 2 6 24 120]\n" ] } ], "source": [ "# cumprod方法,计算数组元素的累积乘积\n", "print \"factorials array: \", b.cumprod()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.5" } }, "nbformat": 4, "nbformat_minor": 0 }