notebooks/numpy.ipynb
2020-09-07 14:54:31 +08:00

3416 lines
122 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 基础知识\n",
"\n",
"NumPy 主要的数据对象是多维数组。它是一个由元素(通常是数字)组成的表,其中所有的元素必须是相同的类型。通过`tuple`可以对表中的元素进行索引即可进行访问或取值等操作。在NumPy中每一维也称为一轴。\n",
"\n",
"举个粟子,一个表示三维座标的点 `[1, 2, 1]` 只有一个轴。这个轴上有3个元素所以它的长度为3。下面的例子有2个轴第一个轴长度为2第二个轴长度为3。\n",
"\n",
"```\n",
"[[ 1, 0, 0],\n",
" [ 0, 1, 2]]\n",
"```\n",
"\n",
"NumPy 中的数组类为 `ndarray`, 别名为 `array`。 注意`numpy.array`跟Python标准库里只能处理一维数据的`array.array`完全不是一回事。`ndarray`中比较重要的属性如下:\n",
"\n",
"* `ndarray.ndim` : 维度\n",
"* `ndarray.shape` : 多维数组的形状,由一个`tuple`表示,它的长度即是多维数组的维度,其中每个元素代表它对应轴的长度。比如一个`n`行`m`列的矩阵,它的`shape`就是`(n, m)`。\n",
"* `ndarray.size` : 多维数组的元素数量。等于 `shape` 中各个元素的连乘。\n",
"* `ndarray.dtype` : 多数数组的元素类型。除了 NumPy 提供的基本类型如 `numpy.int32`、`numpy.int16`、`numpy.float64`之外,你也可以创建自定义类型或 Python 的类型。\n",
"* `ndarray.itemsize` : 每个元素占用的字节数,主要由 `ndarray.dtype` 决定\n",
"* `ndarray.data` : 实际存储所有元素的缓冲区。一般情况不会用到这个属性,而是通过索引机制来访问数组内部的元素。\n",
"\n",
"## 基本操作"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np"
]
},
{
"cell_type": "code",
"execution_count": 5,
"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": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.arange(15).reshape(3, 5)\n",
"a"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(3, 5)"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a.shape"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"2"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a.ndim"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"dtype('int64')"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a.dtype"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"8"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a.itemsize"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"numpy.ndarray"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"type(a)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([6, 7, 8])"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"b = np.array([6, 7 , 8])\n",
"b"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"numpy.ndarray"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"type(b)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 多维数组的创建\n",
"\n",
"创建多维数组的方式有多种。最简单的是通过将Python的数列(一组有序的数字序列,如`list`或`tuple`)传入`numpy.array`函数来创建。其元素类型将会自动推导成为NumPy的类型。"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([1, 2, 3])"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import numpy as np\n",
"\n",
"a = np.array([1, 2, 3])\n",
"a"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"dtype('int64')"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a.dtype"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([1.2, 2.3, 3.4])"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"b = np.array([1.2, 2.3, 3.4])\n",
"b"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"dtype('float64')"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"b.dtype"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"要特别注意传入的参数是__一个__ 数列而不是__多个__参数。比如 `np.array(1, 2, 3)` 这样的调用方式是错误的,会引发异常。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`array` 根据传入数列的深度自动生成对应维度的多维数组。"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1, 2, 3],\n",
" [3, 4, 6]])"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([\n",
" (1, 2, 3),\n",
" (3, 4, 6)\n",
"])\n",
"a"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(2, 3)"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a.shape"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[[1, 2, 3],\n",
" [2, 3, 4]],\n",
"\n",
" [[3, 4, 5],\n",
" [4, 5, 6]]])"
]
},
"execution_count": 40,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"b = np.array([\n",
" [\n",
" [1, 2, 3],\n",
" [2, 3, 4],\n",
" ],\n",
" [\n",
" [3, 4, 5],\n",
" [4, 5, 6]\n",
" ]\n",
"])\n",
"b"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(2, 2, 3)"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"b.shape"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"注意,多维数组的每个轴上的每个元素的`shape`必须是一致的。如以下的Python `list` 是合法的但不能转换成NumPy的多维数组"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"<ipython-input-26-ab70420eb76c>:11: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray\n",
" ndl = np.array(l)\n"
]
}
],
"source": [
"l = [\n",
" [\n",
" [1, 2, 3],\n",
" [2, 3, 4],\n",
" ],\n",
" [\n",
" [3, 4, 5]\n",
" ]\n",
"]\n",
"\n",
"ndl = np.array(l) # won't success"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"一般而言,我们不能预先知道一个多维数组元素取值,但它的`shape`往往是已知的就像是写一个函数虽然实参会是什么值不知道但有多少个形数是确定的。因此NumPy提供了若干个函数用于初始化多维数组。这样就能避免增量分配带来的时间损耗。\n",
"\n",
"`zeros`函数用于初始化一个填满`0`的多维数组,`ones`函数则初始化一个填满`1`的多维数组,`empty`函数则只分配内存空间,其元素值是随机的,取决于所分配内存块当时的状态而定。若不指定`dtype`则默认使用`float64`类型"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[0., 0., 0., 0.],\n",
" [0., 0., 0., 0.],\n",
" [0., 0., 0., 0.]])"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.zeros((3, 4))"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[[1, 1, 1, 1],\n",
" [1, 1, 1, 1],\n",
" [1, 1, 1, 1]],\n",
"\n",
" [[1, 1, 1, 1],\n",
" [1, 1, 1, 1],\n",
" [1, 1, 1, 1]]], dtype=int16)"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.ones((2, 3, 4), dtype=np.int16)"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[6.93551934e-310, 6.93551934e-310, 0.00000000e+000],\n",
" [0.00000000e+000, 0.00000000e+000, 0.00000000e+000]])"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.empty((2, 3))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"为了方便创建等差数列NumPy提供了`arange`函数类似于Python内置的`range`函数,但返回不是迭代器,而是一个多维数组。"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([10, 15, 20, 25])"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.arange(10, 30, 5)"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8])"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.arange(0, 2, 0.3) # it accepts float arguments"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"给`arange`传入浮点时,受精度影响很难准确地对元素的个数进行预测。因此,针对浮点步进而又需要确定元素个数的场景,建议采用`linspace`函数。"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([0. , 0.25, 0.5 , 0.75, 1. , 1.25, 1.5 , 1.75, 2. ])"
]
},
"execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.linspace(0, 2, 9) # 9 numbers from 0 to 2"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"((100,), (100,), 3.173325912716963, -0.03172793349806786)"
]
},
"execution_count": 42,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x = np.linspace(0, 2*np.pi, 100)\n",
"y = np.sin(x)\n",
"x.shape, y.shape, x[50], y[50]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 多维数组的打印\n",
"\n",
"多维数组的打印遵循以下几个原则:\n",
"\n",
"* 最后一个轴的元素从左到右打印\n",
"* 倒数第二个轴从上往下打印\n",
"* 其它轴同样从上往下打印,但元素之间以空行隔开"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"a= [0 1 2 3 4 5]\n",
"b= [[ 0 1 2 3]\n",
" [ 4 5 6 7]\n",
" [ 8 9 10 11]]\n",
"c= [[[ 0 1 2 3]\n",
" [ 4 5 6 7]\n",
" [ 8 9 10 11]]\n",
"\n",
" [[12 13 14 15]\n",
" [16 17 18 19]\n",
" [20 21 22 23]]]\n"
]
}
],
"source": [
"a = np.arange(6)\n",
"print('a=', a)\n",
"\n",
"b = np.arange(12).reshape(3, 4)\n",
"print('b=', b)\n",
"\n",
"c = np.arange(24).reshape(2, 3, 4)\n",
"print('c=', c)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 基本操作\n",
"\n",
"一般的算术操作符在数组上__按元素__为单位进行操作同时返回一个新的数组实例。"
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"a= [2 3 4 5]\n",
"b= [0 1 2 3]\n",
"c=a-b= [2 2 2 2]\n",
"b**2= [0 1 4 9]\n",
"10*np.sin(a)= [ 9.09297427 1.41120008 -7.56802495 -9.58924275]\n",
"a<35= [ True True True True]\n"
]
}
],
"source": [
"a = np.array([2, 3, 4, 5])\n",
"print('a=', a)\n",
"b = np.arange(4)\n",
"print('b=', b)\n",
"c = a - b\n",
"print('c=a-b=', c)\n",
"print('b**2=', b**2)\n",
"print('10*np.sin(a)=', 10*np.sin(a))\n",
"print('a<35=', a<35)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"不同于许多矩阵语言(如MATLAB),乘法操作符`*`指代矩阵乘法在NumPy中则是按元素操作。矩阵乘法通过`@`操作符或者`dot`函数实现。"
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"A * B = [[2 0]\n",
" [0 4]]\n",
"A @ B = [[5 4]\n",
" [3 4]]\n",
"A.dot(B) = [[5 4]\n",
" [3 4]]\n"
]
}
],
"source": [
"A = np.array([\n",
" [1, 1],\n",
" [0, 1],\n",
"])\n",
"B = np.array([\n",
" [2, 0],\n",
" [3, 4]\n",
"])\n",
"print('A * B = ', A * B)\n",
"print('A @ B = ', A @ B)\n",
"print('A.dot(B) = ', A.dot(B))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"一些操作符,如`+=`和`*=`等,则会修改已有数组本身,而不会产生新的数组。"
]
},
{
"cell_type": "code",
"execution_count": 52,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([3, 5, 7])"
]
},
"execution_count": 52,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([1, 2, 3])\n",
"b = np.array([2, 3, 4])\n",
"a += b\n",
"a"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在拥有不同元素类型的矩阵间进行运算操作时NumPy会自动进行向上类型转换。"
]
},
{
"cell_type": "code",
"execution_count": 54,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"dtype('int16')"
]
},
"execution_count": 54,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([1, 2, 3], dtype=np.int8)\n",
"b = np.array([2, 3, 4], dtype=np.int16)\n",
"c = a + b\n",
"c.dtype"
]
},
{
"cell_type": "code",
"execution_count": 56,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"dtype('float64')"
]
},
"execution_count": 56,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([1, 2, 3], dtype=np.int32)\n",
"b = np.array([1, 2, 3], dtype=np.float64)\n",
"c = a * b\n",
"c.dtype"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`ndarray` 上实现了许多一元操作符,如求总操作等。"
]
},
{
"cell_type": "code",
"execution_count": 60,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"a = [[ 0 1 2 3]\n",
" [ 4 5 6 7]\n",
" [ 8 9 10 11]]\n",
"a.sum() 66\n",
"a.min() 0\n",
"a.max() 11\n"
]
}
],
"source": [
"a = np.arange(12).reshape((3, 4))\n",
"print('a = ', a)\n",
"print('a.sum()', a.sum())\n",
"print('a.min()', a.min())\n",
"print('a.max()', a.max())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"若不传入任何参数,这些操作在数组上的表现就跟操作一维数组一样,即不会考虑`ndarray`的`shape`。通过给这些函数传入`axis`参数,即可达到对多维数组上特定轴进行操作的目的"
]
},
{
"cell_type": "code",
"execution_count": 61,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 6, 22, 38])"
]
},
"execution_count": 61,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.arange(12).reshape((3, 4))\n",
"a.sum(axis=1) # 被指定的维将会被统计变成一个标量"
]
},
{
"cell_type": "code",
"execution_count": 63,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0, 1, 2, 3],\n",
" [ 4, 6, 8, 10],\n",
" [12, 15, 18, 21]])"
]
},
"execution_count": 63,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a.cumsum(axis=0) # 累计求和"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 通用函数\n",
"\n",
"NumPy 提供一些常用的数学函数,如 `sin`, `cos`, `exp` 等。这些函数亦称通用函数`ufunc`它们__按元素__为单元进行运算 产生一个新的数组。"
]
},
{
"cell_type": "code",
"execution_count": 64,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([0, 1, 2])"
]
},
"execution_count": 64,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.arange(3)\n",
"a"
]
},
{
"cell_type": "code",
"execution_count": 65,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([1. , 2.71828183, 7.3890561 ])"
]
},
"execution_count": 65,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.exp(a) # 自然对数为底"
]
},
{
"cell_type": "code",
"execution_count": 66,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([0. , 1. , 1.41421356])"
]
},
"execution_count": 66,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.sqrt(a)"
]
},
{
"cell_type": "code",
"execution_count": 68,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([1, 2, 3])"
]
},
"execution_count": 68,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"b = np.arange(1, 4)\n",
"b"
]
},
{
"cell_type": "code",
"execution_count": 69,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([1, 3, 5])"
]
},
"execution_count": 69,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.add(a, b)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 索引、分片及迭代\n",
"\n",
"只有一个轴的数组其索引、分片和迭代的形式与一般的 Python 列表一致"
]
},
{
"cell_type": "code",
"execution_count": 77,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 0, 1, 8, 27, 64, 125, 216, 343, 512, 729])"
]
},
"execution_count": 77,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.arange(10) ** 3\n",
"a"
]
},
{
"cell_type": "code",
"execution_count": 71,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"8"
]
},
"execution_count": 71,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[2]"
]
},
{
"cell_type": "code",
"execution_count": 78,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 0, 8, 64])"
]
},
"execution_count": 78,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[:6:2] # 前6个数中其索引与2整除的元素"
]
},
{
"cell_type": "code",
"execution_count": 79,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 0, 1, -1, -1, -1, 125, 216, 343, 512, 729])"
]
},
"execution_count": 79,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[2:5] = -1 # 更新分片\n",
"a"
]
},
{
"cell_type": "code",
"execution_count": 80,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([729, 512, 343, 216, 125, -1, -1, -1, 1, 0])"
]
},
"execution_count": 80,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[::-1] # 逆序"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"拥有多个轴的数组每个轴都能被索引,索引之间使用逗号`,`分隔"
]
},
{
"cell_type": "code",
"execution_count": 82,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0, 1, 2, 3],\n",
" [ 4, 5, 6, 7],\n",
" [ 8, 9, 10, 11]])"
]
},
"execution_count": 82,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.arange(12).reshape((3, 4))\n",
"a"
]
},
{
"cell_type": "code",
"execution_count": 83,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"11"
]
},
"execution_count": 83,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[2, 3]"
]
},
{
"cell_type": "code",
"execution_count": 87,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[4, 5],\n",
" [8, 9]])"
]
},
"execution_count": 87,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[1:3, :2]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"若传入的索引数量少于数组的轴数,则余下的轴会取其全部。"
]
},
{
"cell_type": "code",
"execution_count": 88,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 4, 5, 6, 7],\n",
" [ 8, 9, 10, 11]])"
]
},
"execution_count": 88,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[1:3] # 相当于 a[1:3, :]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"NumPy 还支持使用省略符`...`,如上面表达式也可以写成 `a[1:3, ...]`。省略符的好处是可以提高可读性,读代码的人马上知道这是一个多维的数组,而不仅仅是一维的。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"对一个多维的数组进行迭代是按它的第一个轴进行的:"
]
},
{
"cell_type": "code",
"execution_count": 89,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[0 1 2 3]\n",
"[4 5 6 7]\n",
"[ 8 9 10 11]\n"
]
}
],
"source": [
"a = np.arange(12).reshape((3, 4))\n",
"\n",
"for b in a:\n",
" print(b)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"假如你想按元素为单位对数组进行操作,则可以利用`flat`属性:"
]
},
{
"cell_type": "code",
"execution_count": 90,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0\n",
"1\n",
"2\n",
"3\n",
"4\n",
"5\n",
"6\n",
"7\n",
"8\n",
"9\n",
"10\n",
"11\n"
]
}
],
"source": [
"for b in a.flat:\n",
" print(b)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 形状操纵\n",
"\n",
"### 数组变形\n",
"\n",
"每个数组都有形状`shape`,它由每个轴上元素的个数决定。"
]
},
{
"cell_type": "code",
"execution_count": 99,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(3, 4)\n"
]
},
{
"data": {
"text/plain": [
"array([[ 17., -5., -15., -15.],\n",
" [ -2., -12., -7., -4.],\n",
" [-15., 11., -3., -4.]])"
]
},
"execution_count": 99,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.floor(10 * np.random.randn(3, 4))\n",
"print(a.shape)\n",
"a"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"数组的形状可以通过一些命令来改变。注意下面几个命令都返回一个新的数组实例。"
]
},
{
"cell_type": "code",
"execution_count": 100,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 17., -5., -15., -15., -2., -12., -7., -4., -15., 11., -3.,\n",
" -4.])"
]
},
"execution_count": 100,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a.ravel() # 返回一个打平的数组"
]
},
{
"cell_type": "code",
"execution_count": 104,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 17., -5., -15., -15., -2., -12., -7., -4., -15., 11., -3.,\n",
" -4.])"
]
},
"execution_count": 104,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"b = a.reshape(12)\n",
"b"
]
},
{
"cell_type": "code",
"execution_count": 106,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0., -5., -15., -15.],\n",
" [ -2., -12., -7., -4.],\n",
" [-15., 11., -3., -4.]])"
]
},
"execution_count": 106,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"b[0] = 0 # 两个数组虽然shape不同但内部元素依然使用同一块内存空间\n",
"a"
]
},
{
"cell_type": "code",
"execution_count": 107,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0., -2., -15.],\n",
" [ -5., -12., 11.],\n",
" [-15., -7., -3.],\n",
" [-15., -4., -4.]])"
]
},
"execution_count": 107,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a.T # 返回转置的数组"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"正常情况下, `ravel`返回的数组元素存储顺序遵循C语言风格即遵守最右边的索引“变化最快”原则因此`a[0, 0]` 的下一个元素是 `a[0, 1]`。当对数组实施变形时该数组也将会被认为是C语言风格的。一般而言NumPy创建的数组皆遵守这个原则所以 `ravel()` 通常都不需要拷贝元素数据,但是,如果数组是由分片或其它一些特殊的方法创建时,可能不需要进行数据拷贝。\n",
"另外,`ravel` 和 `reshape` 函数也可以指定使用 Fortran风格的数组即最左边的索引“变化最快”原则来存储元素数据。\n",
"\n",
"`reshape`函数返回的新数组实例,`resize`函数则直接修改数组本身的形状。"
]
},
{
"cell_type": "code",
"execution_count": 108,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0., -5., -15.],\n",
" [-15., -2., -12.],\n",
" [ -7., -4., -15.],\n",
" [ 11., -3., -4.]])"
]
},
"execution_count": 108,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a.resize(4, 3)\n",
"a"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"如果在变形操作中给轴长度参数传入`-1`,则其轴长度会自动计算。"
]
},
{
"cell_type": "code",
"execution_count": 109,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0., -5., -15., -15., -2., -12.],\n",
" [ -7., -4., -15., 11., -3., -4.]])"
]
},
"execution_count": 109,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a.reshape(2, -1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 数组间的堆叠\n",
"\n",
"若干个数据组可以沿着指定方向进行堆叠"
]
},
{
"cell_type": "code",
"execution_count": 115,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[0, 1],\n",
" [2, 3]])"
]
},
"execution_count": 115,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.arange(4).reshape(2, 2)\n",
"a"
]
},
{
"cell_type": "code",
"execution_count": 116,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[4, 5],\n",
" [6, 7]])"
]
},
"execution_count": 116,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"b = np.arange(4, 8).reshape(2, 2)\n",
"b"
]
},
{
"cell_type": "code",
"execution_count": 118,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[0, 1],\n",
" [2, 3],\n",
" [4, 5],\n",
" [6, 7]])"
]
},
"execution_count": 118,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.vstack((a, b)) # 注意接受的参数是一个tuple"
]
},
{
"cell_type": "code",
"execution_count": 119,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[0, 1, 4, 5],\n",
" [2, 3, 6, 7]])"
]
},
"execution_count": 119,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.hstack((a, b))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"按列堆叠函数`column_stack`用于将一系列一维数组当成列来组合。当传入的数组都是2维时其效果相当于`hstack`"
]
},
{
"cell_type": "code",
"execution_count": 120,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[0, 1, 4, 5],\n",
" [2, 3, 6, 7]])"
]
},
"execution_count": 120,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.column_stack((a, b))"
]
},
{
"cell_type": "code",
"execution_count": 121,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1, 5],\n",
" [2, 6],\n",
" [3, 7],\n",
" [4, 8]])"
]
},
"execution_count": 121,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"c = np.array([1, 2, 3, 4])\n",
"d = np.array([5, 6, 7, 8])\n",
"np.column_stack((c, d))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"既然有`column_stack`,相对地就有`row_stack` 但其实它只是`vstack`的别名。"
]
},
{
"cell_type": "code",
"execution_count": 122,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 122,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.column_stack is np.hstack"
]
},
{
"cell_type": "code",
"execution_count": 123,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 123,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.row_stack is np.vstack"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"总的来讲对于维度大于2的数组`hstack`沿着第二个轴进行堆叠,`vstack`则沿着第一个轴进行堆叠,而 `concatenate`函数则允许传入可选的参数来指定沿着哪个轴进行堆叠。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 数组的拆分\n",
"\n",
"通过`hsplit`,可以将数组水平方向拆分,传入一个数字来得到若干个相等大小的数组,也可传入一个`tuple`来达到根据列下标进行拆分的目的。"
]
},
{
"cell_type": "code",
"execution_count": 126,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],\n",
" [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]])"
]
},
"execution_count": 126,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.arange(24).reshape(2, -1)\n",
"a"
]
},
{
"cell_type": "code",
"execution_count": 128,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[array([[ 0, 1, 2, 3],\n",
" [12, 13, 14, 15]]),\n",
" array([[ 4, 5, 6, 7],\n",
" [16, 17, 18, 19]]),\n",
" array([[ 8, 9, 10, 11],\n",
" [20, 21, 22, 23]])]"
]
},
"execution_count": 128,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.hsplit(a, 3)"
]
},
{
"cell_type": "code",
"execution_count": 135,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[array([[ 0, 1, 2],\n",
" [12, 13, 14]]),\n",
" array([[ 3, 4, 5, 6, 7],\n",
" [15, 16, 17, 18, 19]]),\n",
" array([[ 8, 9],\n",
" [20, 21]]),\n",
" array([[10, 11],\n",
" [22, 23]])]"
]
},
"execution_count": 135,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.hsplit(a, (3, 8, 10))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"对应地,`vsplit`沿垂直方向进行拆,`array_split`则允许指定按某一轴进行拆分。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 复制与视图\n",
"\n",
"当你在操作数组时,有时会导致数组的数据被复制到新的数组,有时则不会。这种状态容易导致新手感到困扰。其实,简单来讲,大致上有三种情形:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 完全不复制\n",
"\n",
"简单地赋值操作不会引发数据复制"
]
},
{
"cell_type": "code",
"execution_count": 137,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 137,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([1, 2, 3, 4])\n",
"b = a # 不会创建新的对象\n",
"b is a # a 和 b 是同一对象的两个名称"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Python 对于可变对象使用传引用的方式进行变量传递,所以函数调用也不会引发数据复制"
]
},
{
"cell_type": "code",
"execution_count": 140,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"id of a 140373490450640\n",
"id of x 140373490450640\n"
]
}
],
"source": [
"def f(x):\n",
" print('id of x', id(x))\n",
" \n",
"print('id of a', id(a))\n",
"f(a)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 视图或浅拷贝\n",
"\n",
"不同的数组间可共享相同的数据(即使用同一内存空间)。视图方法`view`创建的数组对象即属于这种情形"
]
},
{
"cell_type": "code",
"execution_count": 141,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 141,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"c = a.view()\n",
"c is a # c 是一个新的对象,它不是 a"
]
},
{
"cell_type": "code",
"execution_count": 142,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 142,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"c.base is a # 表示 c 是基于 a 的"
]
},
{
"cell_type": "code",
"execution_count": 143,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 143,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"c.flags.owndata # c 没有属于自己的数据"
]
},
{
"cell_type": "code",
"execution_count": 144,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(4,)"
]
},
"execution_count": 144,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"c = c.reshape((2, 2)) # a 的 shape 不因 c 的 shape 改变而改变\n",
"a.shape"
]
},
{
"cell_type": "code",
"execution_count": 146,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([100, 2, 3, 4])"
]
},
"execution_count": 146,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"c[0, 0] = 100 # 修改 c 的数据即是修改 a 的数据\n",
"a"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"数组的分片其实就是返回一个 `view` 对象"
]
},
{
"cell_type": "code",
"execution_count": 148,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([2, 3])"
]
},
"execution_count": 148,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s = a[1:3]\n",
"s"
]
},
{
"cell_type": "code",
"execution_count": 149,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([100, 200, 200, 4])"
]
},
"execution_count": 149,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s[:] = 200\n",
"a"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 深拷贝\n",
"\n",
"`copy`方法在创建一个新数组的同时,也会对原数据的数据进行一个完全的拷贝操作"
]
},
{
"cell_type": "code",
"execution_count": 150,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 150,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"d = d.copy()\n",
"d is a # d 不是 a"
]
},
{
"cell_type": "code",
"execution_count": 151,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 151,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"d.base is a # d 也不基于 a"
]
},
{
"cell_type": "code",
"execution_count": 153,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([100, 200, 200, 4])"
]
},
"execution_count": 153,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"d[:] = 0 # 修改 d 的数据完全不影响 a\n",
"a"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在分片之后,若原来的数组以后不会再被使用,则应调用 `copy` 方法对数据进行拷贝,然后释放原数组。特别是当原数组是一个巨大无比的中间变量时,可以节省大量的内存。"
]
},
{
"cell_type": "code",
"execution_count": 154,
"metadata": {},
"outputs": [],
"source": [
"a = np.random.randn(100)\n",
"b = a[20:30].copy() # 若不调用 copy , 则返回的是视图,它保持着对 a 的引用,只有 b 被回收后 a 才能被回收\n",
"del a # copy 后的 b 与 a 没有引用关系,可以被回收 "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 中级知识\n",
"\n",
"\n",
"## 广播法则\n",
"\n",
"在对多个数组进行运算时,这些数组的形状常常并不是一致的,需要一种有意义的法则来统一处理不同形状数组间的运算问题,因此有了广播法则。\n",
"\n",
"广播的第一条规则即是当输入的多个数组的维度不一致时将以最高维度的数组的轴数为准向低维的数组插入若干个长度为1的新轴直至所有数组的轴数相等。如 `(2, 3, 4), (5), (2, 3)` 将被调整为 `(2, 3, 4), (1, 1, 5), (1, 2, 3)`\n",
"\n",
"第二条规则是数组中长度为1的轴将以所有数组中同维的最长数为准进行扩展扩展元素的值被认为等于扩展前同一轴上的值。"
]
},
{
"cell_type": "code",
"execution_count": 156,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(3, 3)\n",
"(3,)\n"
]
},
{
"data": {
"text/plain": [
"array([[0, 0, 0],\n",
" [3, 3, 3],\n",
" [6, 6, 6]])"
]
},
"execution_count": 156,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([\n",
" [1, 2, 3],\n",
" [4, 5, 6],\n",
" [7, 8, 9],\n",
"])\n",
"print(a.shape)\n",
"b = np.array([-1, -2, -3])\n",
"print(b.shape)\n",
"a + b"
]
},
{
"cell_type": "code",
"execution_count": 157,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(1, 3)\n"
]
},
{
"data": {
"text/plain": [
"array([[0, 0, 0],\n",
" [3, 3, 3],\n",
" [6, 6, 6]])"
]
},
"execution_count": 157,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"c = np.array([\n",
" [-1, -2, -3]\n",
"])\n",
"print(c.shape)\n",
"a + c"
]
},
{
"cell_type": "code",
"execution_count": 158,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(1, 1)\n"
]
},
{
"data": {
"text/plain": [
"array([[0, 1, 2],\n",
" [3, 4, 5],\n",
" [6, 7, 8]])"
]
},
"execution_count": 158,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"d = np.array([\n",
" [-1]\n",
"])\n",
"print(d.shape)\n",
"a + d"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 高级索引及索引技巧\n",
"\n",
"除了使用之前提到过的标准 Python 索引方式之外NumPy 还提供了额外的索引方式。比如,支持通过整数数组或布尔数组的方式进行索引。 \n",
"\n",
"### 整数索引数组"
]
},
{
"cell_type": "code",
"execution_count": 163,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"a= [ 0 2 4 6 8 10 12 14 16 18 20 22]\n"
]
},
{
"data": {
"text/plain": [
"array([ 2, 2, 6, 16, 10])"
]
},
"execution_count": 163,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.arange(12) * 2\n",
"print('a=', a)\n",
"i = np.array([1, 1, 3, 8 , 5])\n",
"a[i]"
]
},
{
"cell_type": "code",
"execution_count": 164,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 6, 8],\n",
" [18, 14]])"
]
},
"execution_count": 164,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"j = np.array([[3, 4], [9, 7]])\n",
"a[j]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"当被索引的数组 `a` 是一个多维数组时,传入一维索引数组则代表对`a`的第一个轴进行引用。下面的例子演示如何使用色板将__索引图像__转换成__彩色图像__"
]
},
{
"cell_type": "code",
"execution_count": 165,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[[ 0, 0, 0],\n",
" [255, 0, 0],\n",
" [ 0, 255, 0],\n",
" [ 0, 0, 0]],\n",
"\n",
" [[ 0, 0, 0],\n",
" [ 0, 0, 255],\n",
" [255, 255, 255],\n",
" [ 0, 0, 0]]])"
]
},
"execution_count": 165,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"palette = np.array([ # 色板\n",
" [ 0, 0, 0], # 黑色\n",
" [255, 0, 0], # 红色\n",
" [ 0, 255, 0], # 绿色\n",
" [ 0, 0, 255], # 蓝色\n",
" [255, 255, 255], # 白色\n",
"])\n",
"\n",
"image = np.array([ # 索引图像\n",
" [0, 1, 2, 0], # 每个值为其颜色在色板上的索引值\n",
" [0, 3, 4, 0],\n",
"])\n",
"\n",
"palette[image] # 将 image 作为索引数组对色板进行索引即可得到彩色图像"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"此外,也可对多维数组使用多个索引数组,传入的索引数组间必须拥有相同的形状。"
]
},
{
"cell_type": "code",
"execution_count": 179,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0, 1, 2, 3],\n",
" [ 4, 5, 6, 7],\n",
" [ 8, 9, 10, 11]])"
]
},
"execution_count": 179,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.arange(12).reshape(3, 4)\n",
"i = np.array([[0, 1], [1, 2]])\n",
"j = np.array([[2, 1], [3, 3]])\n",
"a"
]
},
{
"cell_type": "code",
"execution_count": 178,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[[ 0, 1, 2, 3],\n",
" [ 4, 5, 6, 7]],\n",
"\n",
" [[ 4, 5, 6, 7],\n",
" [ 8, 9, 10, 11]]])"
]
},
"execution_count": 178,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[i] # 取i行"
]
},
{
"cell_type": "code",
"execution_count": 180,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 2, 6],\n",
" [ 6, 10]])"
]
},
"execution_count": 180,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[i, 2] # 取i行再取第2列"
]
},
{
"cell_type": "code",
"execution_count": 181,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 2, 5],\n",
" [ 7, 11]])"
]
},
"execution_count": 181,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[i, j] # 取i行再取j列i 和 j 的 shape 必须相同。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在 Python 语言里,`a[i, j]` 和 `a[(i, j)]` 在语法上等交,因此,可以把 `i` 和 `j` 放到 `tuple` 里面再利用它来进行索引。"
]
},
{
"cell_type": "code",
"execution_count": 182,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 2, 5],\n",
" [ 7, 11]])"
]
},
"execution_count": 182,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"l = (i, j)\n",
"a[l]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"然而,将它们放到数组则是不行的。因为它就变成了索引数组,所有元素都将指向被索引数组的第一个轴。"
]
},
{
"cell_type": "code",
"execution_count": 186,
"metadata": {},
"outputs": [
{
"ename": "IndexError",
"evalue": "index 3 is out of bounds for axis 0 with size 3",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-186-688953b2ce97>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0ms\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0ma\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0ms\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;31m# a 的第一个轴长度只有3\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mIndexError\u001b[0m: index 3 is out of bounds for axis 0 with size 3"
]
}
],
"source": [
"s = np.array([i, j])\n",
"a[s] # a 的第一个轴长度只有3"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"索引数组还有一个常见的用途:在时间相关的序列里面查找最大值。"
]
},
{
"cell_type": "code",
"execution_count": 188,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 20. , 51.25, 82.5 , 113.75, 145. ])"
]
},
"execution_count": 188,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"time = np.linspace(20, 145, 5)\n",
"time"
]
},
{
"cell_type": "code",
"execution_count": 190,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0. , 0.84147098, 0.90929743, 0.14112001],\n",
" [-0.7568025 , -0.95892427, -0.2794155 , 0.6569866 ],\n",
" [ 0.98935825, 0.41211849, -0.54402111, -0.99999021],\n",
" [-0.53657292, 0.42016704, 0.99060736, 0.65028784],\n",
" [-0.28790332, -0.96139749, -0.75098725, 0.14987721]])"
]
},
"execution_count": 190,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data = np.sin(np.arange(20)).reshape(5, 4)\n",
"data"
]
},
{
"cell_type": "code",
"execution_count": 209,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([2, 0, 3, 1])"
]
},
"execution_count": 209,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ind = data.argmax(axis=0)\n",
"ind"
]
},
{
"cell_type": "code",
"execution_count": 212,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 82.5 , 20. , 113.75, 51.25])"
]
},
"execution_count": 212,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"time_max = time[ind]\n",
"time_max"
]
},
{
"cell_type": "code",
"execution_count": 214,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([0.98935825, 0.84147098, 0.99060736, 0.6569866 ])"
]
},
"execution_count": 214,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data_max = data[ind, range(data.shape[1])]\n",
"data_max"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"此外,还可以通过多个索引向元素进行赋值"
]
},
{
"cell_type": "code",
"execution_count": 217,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([0, 0, 2, 0, 0])"
]
},
"execution_count": 217,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.arange(5)\n",
"a[[1, 3, 4]] = 0\n",
"a"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"然而,若索引数组中存在重复索引时,赋值操作将会依次进行,该元素的值为最后赋值的值。 "
]
},
{
"cell_type": "code",
"execution_count": 218,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([2, 1, 3, 3, 4])"
]
},
"execution_count": 218,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.arange(5)\n",
"a[[0, 0, 2]] = [1, 2, 3]\n",
"a"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"但要注意,如果使用了 `+=` 操作符,则累加操作只会进行一次。"
]
},
{
"cell_type": "code",
"execution_count": 219,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([1, 1, 3, 3, 4])"
]
},
"execution_count": 219,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.arange(5)\n",
"a[[0, 0, 2]] += 1\n",
"a"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"虽然0在索引数组中出现多次但是第0个元素只会被累加一次。因为 Python 要求表达式 `a += 1` 的语义与 `a = a + 1`一致。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 布尔索引数组\n",
"\n",
"当我们使用整数索引数组进行索引时,提供的是所需元素的索引值。布尔数组则不然,需要显式地说明哪些元素需要,哪些不需要。\n",
"\n",
"用人话讲,就是布尔索引数组采用一个与被索引数组形状大小一致的布尔数组来进行元素过滤。"
]
},
{
"cell_type": "code",
"execution_count": 220,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[False, False, False, False],\n",
" [False, True, True, True],\n",
" [ True, True, True, True]])"
]
},
"execution_count": 220,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.arange(12).reshape(3, 4)\n",
"b = a > 4\n",
"b"
]
},
{
"cell_type": "code",
"execution_count": 221,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 5, 6, 7, 8, 9, 10, 11])"
]
},
"execution_count": 221,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[b]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"布尔索引数组的这种特性,尤其适合赋值操作的场景。"
]
},
{
"cell_type": "code",
"execution_count": 224,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1j"
]
},
"execution_count": 224,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[a > 4] = 0\n",
"a"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"下面,我们来看一下如何利用布尔索引数组生成 Mandelbrot 集的图像"
]
},
{
"cell_type": "code",
"execution_count": 231,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[0 0 0 ... 0 0 0]\n",
" [0 0 0 ... 0 0 0]\n",
" [0 0 0 ... 0 0 0]\n",
" ...\n",
" [0 0 0 ... 0 0 0]\n",
" [0 0 0 ... 0 0 0]\n",
" [0 0 0 ... 0 0 0]]\n"
]
},
{
"data": {
"text/plain": [
"<matplotlib.image.AxesImage at 0x7fab3ad51d30>"
]
},
"execution_count": 231,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"\n",
"\n",
"def mandelbrot(h, w, maxit=20):\n",
" \"\"\"返回一个指定大小(h,w)的 Mandelbrot 分形图像\"\"\"\n",
" y, x = np.ogrid[-1.4 : 1.4 : h*1j, -2 : 0.8 : w*1j]\n",
" c = x + y * 1j\n",
" z = c\n",
" divtime = maxit + np.zeros(z.shape, dtype=int)\n",
" for i in range(maxit):\n",
" z = z ** 2 + c\n",
" diverge = z * np.conj(z) > 2 ** 2\n",
" div_now = diverge & (divtime == maxit)\n",
" divtime[div_now] = i\n",
" z[diverge] = 2\n",
" return divtime\n",
"\n",
"\n",
"plt.imshow(mandelbrot(400, 400))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"另一种使用方式比较接近于整数索引数组,对应于多维数组的每一个轴,可以分别给出一个一维的数组来指示所需要的分片:"
]
},
{
"cell_type": "code",
"execution_count": 236,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(array([[ 0, 1, 2, 3],\n",
" [ 4, 5, 6, 7],\n",
" [ 8, 9, 10, 11]]),\n",
" array([False, True, True]),\n",
" array([ True, False, True, False]))"
]
},
"execution_count": 236,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.arange(12).reshape(3, 4)\n",
"b1 = np.array([False, True, True])\n",
"b2 = np.array([True, False, True, False])\n",
"a, b1, b2"
]
},
{
"cell_type": "code",
"execution_count": 237,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 4, 5, 6, 7],\n",
" [ 8, 9, 10, 11]])"
]
},
"execution_count": 237,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[b1, :]"
]
},
{
"cell_type": "code",
"execution_count": 238,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0, 2],\n",
" [ 4, 6],\n",
" [ 8, 10]])"
]
},
"execution_count": 238,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[:, b2]"
]
},
{
"cell_type": "code",
"execution_count": 239,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 4, 10])"
]
},
"execution_count": 239,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a[b1, b2]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"注意每个一维布尔索引数组的长度必须与对应被索引数组的轴长度相同。如上所示,`b1`的长度为3与`a`的第一个轴长度相同,`b2`的长度为4与`a`的第二个轴长度相同"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### ix_() 函数\n",
"\n",
"`ix_` 函数可用于对多个向量进行组合维度扩展。"
]
},
{
"cell_type": "code",
"execution_count": 244,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"((4, 1, 1), (1, 3, 1), (1, 1, 5))"
]
},
"execution_count": 244,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([2, 3, 4, 5])\n",
"b = np.array([8, 5, 4])\n",
"c = np.array([5, 4, 6, 8, 3])\n",
"ax, bx, cx = np.ix_(a, b, c)\n",
"ax.shape, bx.shape, cx.shape"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"这样我们就可以很方便地实现一些向量运算,如 `a+b*c` ,其中`a`、`b`、`c`都是向量。"
]
},
{
"cell_type": "code",
"execution_count": 245,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[[42, 34, 50, 66, 26],\n",
" [27, 22, 32, 42, 17],\n",
" [22, 18, 26, 34, 14]],\n",
"\n",
" [[43, 35, 51, 67, 27],\n",
" [28, 23, 33, 43, 18],\n",
" [23, 19, 27, 35, 15]],\n",
"\n",
" [[44, 36, 52, 68, 28],\n",
" [29, 24, 34, 44, 19],\n",
" [24, 20, 28, 36, 16]],\n",
"\n",
" [[45, 37, 53, 69, 29],\n",
" [30, 25, 35, 45, 20],\n",
" [25, 21, 29, 37, 17]]])"
]
},
"execution_count": 245,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ax + bx * cx"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 字符串索引\n",
"\n",
"详见 [Structured arrays](https://numpy.org/devdocs/user/basics.rec.html#structured-arrays)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 线性代数\n",
"\n",
"## 基本操作\n",
"\n",
"更多信息请查阅 numpy 文件夹中的 `linalg.py` 文件"
]
},
{
"cell_type": "code",
"execution_count": 246,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1., 2.],\n",
" [3., 4.]])"
]
},
"execution_count": 246,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.array([[1.0, 2.0], [3.0, 4.0]])\n",
"a"
]
},
{
"cell_type": "code",
"execution_count": 247,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1., 3.],\n",
" [2., 4.]])"
]
},
"execution_count": 247,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a.transpose() # 转置"
]
},
{
"cell_type": "code",
"execution_count": 249,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[-2. , 1. ],\n",
" [ 1.5, -0.5]])"
]
},
"execution_count": 249,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.linalg.inv(a) # 逆矩阵"
]
},
{
"cell_type": "code",
"execution_count": 250,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1., 0.],\n",
" [0., 1.]])"
]
},
"execution_count": 250,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.eye(2) # 返回 2x2 单位阵"
]
},
{
"cell_type": "code",
"execution_count": 251,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 7., 10.],\n",
" [15., 22.]])"
]
},
"execution_count": 251,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a @ a # 矩阵乘法"
]
},
{
"cell_type": "code",
"execution_count": 252,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"5.0"
]
},
"execution_count": 252,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.trace(a) # 求主对角线元素的和,即矩阵特征值之和"
]
},
{
"cell_type": "code",
"execution_count": 253,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[-3.],\n",
" [ 4.]])"
]
},
"execution_count": 253,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"y = np.array([[5.], [7.]])\n",
"np.linalg.solve(a, y) # 解线性方程组"
]
},
{
"cell_type": "code",
"execution_count": 255,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(array([-0.37228132, 5.37228132]),\n",
" array([[-0.82456484, -0.41597356],\n",
" [ 0.56576746, -0.90937671]]))"
]
},
"execution_count": 255,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.linalg.eig(a) # 求特征值和特征向量"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 技巧\n",
"\n",
"## 自动变形\n",
"\n",
"在对数组进行维度调整时,可以省略其中某一轴的长度。"
]
},
{
"cell_type": "code",
"execution_count": 256,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(2, 5, 3)"
]
},
"execution_count": 256,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = np.arange(30)\n",
"b = a.reshape((2, -1, 3)) # 其中 -1 将会被自动计算\n",
"b.shape"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 向量堆叠\n",
"\n",
"如何将一组长度相同的行向量堆叠成一个矩阵?在 MATLAB 这样的操作比较简单,假如 `x` 和 `y` 是两个长度一样的向量,只需用 `m = [x;y]` 即可产生一个矩阵。在 NumPy 中,类似的功能需要通过函数实现 `column_stack`, `dstack`, `hstack` 和 '`vstack`。具体采用哪个函数取决于要沿着哪一个轴堆叠。例如:"
]
},
{
"cell_type": "code",
"execution_count": 257,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[0, 2, 4, 6, 8],\n",
" [0, 1, 2, 3, 4]])"
]
},
"execution_count": 257,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x = np.arange(0, 10, 2)\n",
"y = np.arange(0, 5, 1)\n",
"m = np.vstack([x, y])\n",
"m"
]
},
{
"cell_type": "code",
"execution_count": 258,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([0, 2, 4, 6, 8, 0, 1, 2, 3, 4])"
]
},
"execution_count": 258,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"xy = np.hstack([x, y])\n",
"xy"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 直方图\n",
"\n",
"NumPy 的 `histogram` 函数接收一个数组,返回一对向量:数组的直方图、组边向量。注意:`matplotlib` 也有个创建直方图的函数(同MATLAB中的`hist`),它与 NumPy 的 `histogram` 是不一样的。主要区别是 `pylab.hist` 会自动地画出直方图,而`numpy.histogram`只是返回数据。"
]
},
{
"cell_type": "code",
"execution_count": 265,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(array([2.1727921 , 2.41080907, 2.16521854, ..., 2.15062613, 1.61436007,\n",
" 2.09274213]),\n",
" (10000,),\n",
" array([0.00128706, 0.00257412, 0.00257412, 0.00257412, 0.00772237,\n",
" 0.00900943, 0.01415767, 0.03861183, 0.04247301, 0.03989889,\n",
" 0.05663068, 0.08623308, 0.13900258, 0.16088261, 0.24454157,\n",
" 0.30117225, 0.34750645, 0.41700774, 0.51997261, 0.60234451,\n",
" 0.68214229, 0.69501289, 0.78768128, 0.73619884, 0.79540365,\n",
" 0.78896834, 0.72976354, 0.7014482 , 0.69501289, 0.60749275,\n",
" 0.57660329, 0.4478972 , 0.39126652, 0.28186634, 0.24196745,\n",
" 0.20592975, 0.13385434, 0.10425193, 0.07851072, 0.04762125,\n",
" 0.0296024 , 0.03217652, 0.01029649, 0.00900943, 0.0064353 ,\n",
" 0.00772237, 0.00514824, 0.00128706, 0.00257412, 0.00128706]),\n",
" (50,),\n",
" array([0.08106893, 0.15876533, 0.23646173, 0.31415813, 0.39185453,\n",
" 0.46955093, 0.54724733, 0.62494373, 0.70264013, 0.78033653,\n",
" 0.85803293, 0.93572933, 1.01342573, 1.09112213, 1.16881853,\n",
" 1.24651493, 1.32421133, 1.40190773, 1.47960413, 1.55730053,\n",
" 1.63499693, 1.71269333, 1.79038973, 1.86808613, 1.94578253,\n",
" 2.02347893, 2.10117533, 2.17887173, 2.25656814, 2.33426454,\n",
" 2.41196094, 2.48965734, 2.56735374, 2.64505014, 2.72274654,\n",
" 2.80044294, 2.87813934, 2.95583574, 3.03353214, 3.11122854,\n",
" 3.18892494, 3.26662134, 3.34431774, 3.42201414, 3.49971054,\n",
" 3.57740694, 3.65510334, 3.73279974, 3.81049614, 3.88819254,\n",
" 3.96588894]),\n",
" (51,))"
]
},
"execution_count": 265,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"rg = np.random.default_rng(1)\n",
"mu, sigma = 2, 0.5\n",
"v = rg.normal(mu,sigma,10000) # \n",
"plt.hist(v, bins=50, density=1)\n",
"n, bins = np.histogram(v, bins=50, density=True)\n",
"plt.plot(.5*(bins[1:]+bins[:-1]), n)\n",
"v, v.shape, n, n.shape, bins, bins.shape"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.4"
}
},
"nbformat": 4,
"nbformat_minor": 4
}