{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "### 数组的转置和轴对换" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 转置可以使用transpose()方法,也可以使用T属性" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 1, 2, 3, 4],\n", " [ 5, 6, 7, 8, 9],\n", " [10, 11, 12, 13, 14]])" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr = np.arange(15).reshape((3,5))\n", "arr" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 5, 10],\n", " [ 1, 6, 11],\n", " [ 2, 7, 12],\n", " [ 3, 8, 13],\n", " [ 4, 9, 14]])" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr.transpose()" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 5, 10],\n", " [ 1, 6, 11],\n", " [ 2, 7, 12],\n", " [ 3, 8, 13],\n", " [ 4, 9, 14]])" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr.T" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 在矩阵计算时经常使用转置操作,比如,计算矩阵的内积np.dot()" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 1.24971097, -1.15270121, 1.41855366],\n", " [-1.21579815, 0.67722079, -0.63992388],\n", " [-1.14607563, 0.59604011, 1.46181227],\n", " [ 0.39345074, 1.47096921, 0.55652236]])" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr = np.random.randn(4,3)\n", "arr" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 4.50823549, -2.36826025, 1.09441706],\n", " [-2.36826025, 4.3063623 , -0.37861226],\n", " [ 1.09441706, -0.37861226, 4.86840931]])" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.dot(arr.T,arr)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 对于高维数组(>3),transpose需要得到一个由编号组成的元祖才能对这些轴进行转置" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[[ 0, 1, 2, 3],\n", " [ 4, 5, 6, 7]],\n", "\n", " [[ 8, 9, 10, 11],\n", " [12, 13, 14, 15]]])" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr = np.arange(16).reshape((2,2,4))\n", "arr" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[[ 0, 1, 2, 3],\n", " [ 8, 9, 10, 11]],\n", "\n", " [[ 4, 5, 6, 7],\n", " [12, 13, 14, 15]]])" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr.transpose((1,0,2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* swapaxes方法接收一对轴编号。swapaxes也是返回源数据的视图(不会进行任何复制操作" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[[ 0, 1, 2, 3],\n", " [ 4, 5, 6, 7]],\n", "\n", " [[ 8, 9, 10, 11],\n", " [12, 13, 14, 15]]])" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[[ 0, 4],\n", " [ 1, 5],\n", " [ 2, 6],\n", " [ 3, 7]],\n", "\n", " [[ 8, 12],\n", " [ 9, 13],\n", " [10, 14],\n", " [11, 15]]])" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr.swapaxes(1,2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 4.2通用函数:快速的元素级数组函数\n", "* 通用函数(即ufunc)是一种对ndarray中的数据执行元素级运算的函数。你可以将其看做简单函数(接受一个或多个标量值,并产生一个或多个标量值)的矢量化包装器" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr = np.arange(10)\n", "arr" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0. , 1. , 1.41421356, 1.73205081, 2. ,\n", " 2.23606798, 2.44948974, 2.64575131, 2.82842712, 3. ])" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.sqrt(arr)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1.00000000e+00, 2.71828183e+00, 7.38905610e+00, 2.00855369e+01,\n", " 5.45981500e+01, 1.48413159e+02, 4.03428793e+02, 1.09663316e+03,\n", " 2.98095799e+03, 8.10308393e+03])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.exp(arr)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 上述方法也叫一元通用函数。下面介绍几个二元通用函数" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-1.7266767 , 1.2232217 , 0.13346529, 0.20789797, 0.05153854,\n", " -1.39971978, 0.11192313, 0.00818701])" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.random.randn(8)\n", "y = np.random.randn(8)\n", "x" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-0.58431702, 1.18389044, 0.23911619, -0.20529655, -0.22218649,\n", " -0.23151421, -1.83659486, 0.91349072])" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-0.58431702, 1.2232217 , 0.23911619, 0.20789797, 0.05153854,\n", " -0.23151421, 0.11192313, 0.91349072])" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.maximum(x,y)# 返回对应位置元素的较大值" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* modf可以返回多个数组,它会返回浮点数的整数部分和小数部分" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 2.11214818, 5.9728119 , -0.25401792, -10.69556551,\n", " -2.15374894, -0.32658578, -2.63945653])" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr = np.random.randn(7)*5\n", "arr" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0.11214818, 0.9728119 , -0.25401792, -0.69556551, -0.15374894,\n", " -0.32658578, -0.63945653])" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "remainder, whole_part = np.modf(arr)\n", "remainder" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 2., 5., -0., -10., -2., -0., -2.])" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "whole_part" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 下表是一些常见的函数\n", "![一元1](https://upload-images.jianshu.io/upload_images/7178691-1d494e73b61c7ced.png)\n", "![一元2](https://upload-images.jianshu.io/upload_images/7178691-2be79faf68ab6ff8.png)\n", "![一元3](https://upload-images.jianshu.io/upload_images/7178691-4e38d02a66481530.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 二元函数\n", "![二元1](https://upload-images.jianshu.io/upload_images/7178691-eff1e61e5464159f.png)\n", "![二元2](https://upload-images.jianshu.io/upload_images/7178691-eff1e61e5464159f.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 4.3 利用数组进行数据处理\n", "* 用数组表达式代替循环的做法,通常被称为矢量化" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* np.meshgrid函数接受两个一维数组,并产生两个二维矩阵(对应于两个数组中所有的(x,y)对)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[-5. , -5. , -5. , ..., -5. , -5. , -5. ],\n", " [-4.99, -4.99, -4.99, ..., -4.99, -4.99, -4.99],\n", " [-4.98, -4.98, -4.98, ..., -4.98, -4.98, -4.98],\n", " ...,\n", " [ 4.97, 4.97, 4.97, ..., 4.97, 4.97, 4.97],\n", " [ 4.98, 4.98, 4.98, ..., 4.98, 4.98, 4.98],\n", " [ 4.99, 4.99, 4.99, ..., 4.99, 4.99, 4.99]])" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "points = np.arange(-5,5,0.01)\n", "xs,ys = np.meshgrid(points,points)\n", "ys" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[7.07106781, 7.06400028, 7.05693985, ..., 7.04988652, 7.05693985,\n", " 7.06400028],\n", " [7.06400028, 7.05692568, 7.04985815, ..., 7.04279774, 7.04985815,\n", " 7.05692568],\n", " [7.05693985, 7.04985815, 7.04278354, ..., 7.03571603, 7.04278354,\n", " 7.04985815],\n", " ...,\n", " [7.04988652, 7.04279774, 7.03571603, ..., 7.0286414 , 7.03571603,\n", " 7.04279774],\n", " [7.05693985, 7.04985815, 7.04278354, ..., 7.03571603, 7.04278354,\n", " 7.04985815],\n", " [7.06400028, 7.05692568, 7.04985815, ..., 7.04279774, 7.04985815,\n", " 7.05692568]])" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z = np.sqrt(xs**2 + ys**2)\n", "z" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import matplotlib.pyplot as plt\n", "plt.imshow(z,cmap=plt.cm.gray)\n", "plt.colorbar()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 将条件逻辑表述为数组运算\n", "* numpy.where函数是三元表达式x if condition else y的矢量化版本。" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1.2, 2.2, 1.3, 1.4, 2.5]" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "xarr = np.array([1.2,1.2,1.3,1.4,1.5])\n", "yarr = np.array([2.1,2.2,2.3,2.4,2.5])\n", "cond = np.array([True,False,True,True,False])\n", "result = [(x if c else y) for x,y,c in zip(xarr, yarr, cond)]\n", "result" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1.2, 2.2, 1.3, 1.4, 2.5])" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 使用where()改进\n", "result = np.where(cond,xarr,yarr)\n", "result" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* np.where的第二个和第三个参数不必是数组,它们都可以是标量值。在数据分析工作中,where通常用于根据另一个数组而产生一个新的数组。" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[False, False, False, False],\n", " [False, True, True, False],\n", " [ True, True, False, True],\n", " [ True, False, True, False]])" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr = np.random.randn(4,4)\n", "arr > 0" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[-0.02459259, -0.6428239 , -0.76112065, -2.14235712],\n", " [-0.10120677, 0.14290032, 0.56280688, -1.39125445],\n", " [ 0.39828175, 0.07024995, -1.22357901, 0.90811459],\n", " [ 0.83422951, -0.10858237, 0.90184316, -2.57063453]])" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[-2, -2, -2, -2],\n", " [-2, 2, 2, -2],\n", " [ 2, 2, -2, 2],\n", " [ 2, -2, 2, -2]])" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.where(arr>0,2,-2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 也可以将标量和数组结合起来" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[-0.02459259, -0.6428239 , -0.76112065, -2.14235712],\n", " [-0.10120677, 2. , 2. , -1.39125445],\n", " [ 2. , 2. , -1.22357901, 2. ],\n", " [ 2. , -0.10858237, 2. , -2.57063453]])" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.where(arr>0,2,arr)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 数学和统计方法\n", "* sum、mean以及标准差std等聚合计算(aggregation,通常叫做约简(reduction))既可以当做数组的实例方法调用,也可以当做顶级NumPy函数使用。" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0.31996205, 0.69908917, 1.60390967, -0.41760093],\n", " [-0.36385331, -0.2618905 , 1.15295921, -0.10163846],\n", " [ 1.28356236, 0.45163684, 0.3690968 , -0.81384686],\n", " [ 0.14891047, 0.75320511, -1.49658404, 0.61913003],\n", " [ 0.0395804 , 0.97813093, 1.96525592, -1.07168954]])" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr = np.random.randn(5,4)\n", "arr" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.2928662657820542" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr.mean()" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.2928662657820542" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.mean(arr)" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5.857325315641084" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr.sum()" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5.857325315641084" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.sum(arr)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* mean和sum这类的函数可以接受一个axis选项参数,用于计算该轴向上的统计值,最终结果是一个少一维的数组\n", "* axis = 1,按行计算;axis=0,按列计算" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.55133999, 0.10639423, 0.32261228, 0.00616539, 0.47781943])" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr.mean(axis=1)" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 1.42816197, 2.62017154, 3.59463756, -1.78564575])" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr.sum(axis=0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* cumsum和cumprod之类的方法则不聚合,而是产生一个由中间结果组成的数组" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7])" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr = np.arange(8)\n", "arr" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 1, 3, 6, 10, 15, 21, 28], dtype=int32)" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr.cumsum()# 后一个元素值是其位置前面元素的和" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 在多维数组中,累加函数(如cumsum)返回的是同样大小的数组,但是会根据每个低维的切片沿着标记轴计算部分聚类:" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[0, 1, 2],\n", " [3, 4, 5],\n", " [6, 7, 8]])" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr = np.arange(9).reshape(3,3)\n", "arr" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 1, 2],\n", " [ 3, 5, 7],\n", " [ 9, 12, 15]], dtype=int32)" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr.cumsum(axis=0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 表4-5列出了全部的基本数组统计方法" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![1](https://upload-images.jianshu.io/upload_images/7178691-a6c6df3ca8e0b98e.png)\n", "![2](https://upload-images.jianshu.io/upload_images/7178691-866fcde885b1d357.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 用于布尔型数组的方法\n", "* 在上面这些方法中,布尔值会被强制转换为1(True)和0(False)。因此,sum经常被用来对布尔型数组中的True值计数:" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "47" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr = np.random.randn(100)\n", "(arr > 0).sum()# 用于计算arr中大于零的值的个数" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* any用于测试数组中是否存在一个或多个True,而all则检查数组中所有值是否都是True:\n", "* 这两个方法也能用于非布尔型数组,所有非0元素将会被当做True。" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "bools = np.array([True,False,True,True,False])\n", "bools.any()" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "bools.all()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 排序" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 1.02405122, -0.6697276 , -0.21968547, -0.72406011, 0.1925428 ,\n", " 0.07636505])" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr = np.random.randn(6)\n", "arr" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-0.72406011, -0.6697276 , -0.21968547, 0.07636505, 0.1925428 ,\n", " 1.02405122])" ] }, "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr.sort()\n", "arr" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 多维数组可以在任何一个轴向上进行排序,只需将轴编号传给sort即可:" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0.71087653, 0.07317549, -0.5169106 ],\n", " [-0.79285818, 0.2562815 , 0.52803003],\n", " [ 0.32807348, -0.15266984, -0.65285013],\n", " [-0.06786031, 2.69566713, -0.44730785],\n", " [ 0.42299494, 0.95989471, -0.51781003]])" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr = np.random.randn(5,3)\n", "arr" ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [], "source": [ "arr.sort(axis=1)# 按行排序" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[-0.5169106 , 0.07317549, 0.71087653],\n", " [-0.79285818, 0.2562815 , 0.52803003],\n", " [-0.65285013, -0.15266984, 0.32807348],\n", " [-0.44730785, -0.06786031, 2.69566713],\n", " [-0.51781003, 0.42299494, 0.95989471]])" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "arr" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 顶级方法np.sort返回的是数组的已排序副本,而就地排序则会修改数组本身。计算数组分位数最简单的办法是对其进行排序,然后选取特定位置的值:" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-1.7547949961699647" ] }, "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ "large_arr = np.random.randn(1000)\n", "large_arr.sort()\n", "large_arr[int(0.05*len(large_arr))]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 唯一化以及其它的集合逻辑\n", "* np.unique,它用于找出数组中的唯一值并返回已排序的结果:" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array(['Bob', 'Joe', 'Will'], dtype='