diff --git a/_static/custom.css b/_static/custom.css new file mode 100644 index 0000000..194630d --- /dev/null +++ b/_static/custom.css @@ -0,0 +1,3 @@ +html[data-theme="light"] { + --sbt-color-announcement: rgb(125, 125, 125); +} \ No newline at end of file diff --git a/_toc.yml b/_toc.yml index 534b1ff..f32c694 100644 --- a/_toc.yml +++ b/_toc.yml @@ -8,6 +8,7 @@ subtrees: - file: ch-numpy/ndarray - file: ch-numpy/ndarray-slicing-index - file: ch-numpy/random + - file: ch-numpy/ops - file: ch-pandas/index entries: - file: ch-pandas/pandas-intro diff --git a/ch-numpy/binary-ops.ipynb b/ch-numpy/binary-ops.ipynb deleted file mode 100644 index c1ac148..0000000 --- a/ch-numpy/binary-ops.ipynb +++ /dev/null @@ -1,1532 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 二元函数" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "二元运算是指作用于两个对象(例如数组)进行的运算:\n", - "给定集合 `A` ,二元函数 `F` : $A\\times A$ → $A$ 称为集合 `A` 上的二元运算。\n", - "需要注意的是,二元运算的运算结果跟两个输入值必须是同种东西。例如,整数的加法是二元运算,因为整数相加后仍然是整数。" - ] - }, - { - "cell_type": "code", - "execution_count": 87, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 简单操作\n", - "将两个数组各元素进行对应运算" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "在正式开始前,我们先生成数组 `x` 和 `y` 用作演示练习使用。" - ] - }, - { - "cell_type": "code", - "execution_count": 88, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([1, 2, 3, 4])" - ] - }, - "execution_count": 88, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x = np.array([1,2,3,4])\n", - "x" - ] - }, - { - "cell_type": "code", - "execution_count": 89, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([-1.2, 1.4, 1.5, 1.7])" - ] - }, - "execution_count": 89, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "y = np.array([-1.2,1.4,1.5,1.7])\n", - "y" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 基础运算\n", - "对于两个数组个元素对应进行加减乘运算。" - ] - }, - { - "cell_type": "code", - "execution_count": 90, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([-0.2, 3.4, 4.5, 5.7])" - ] - }, - "execution_count": 90, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x+y" - ] - }, - { - "cell_type": "code", - "execution_count": 91, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([2.2, 0.6, 1.5, 2.3])" - ] - }, - "execution_count": 91, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x-y" - ] - }, - { - "cell_type": "code", - "execution_count": 92, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([-1.2, 2.8, 4.5, 6.8])" - ] - }, - "execution_count": 92, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x*y" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 最值计算\n", - "对两个数组间进行元素级最值计算" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 1.最大值计算\n", - "我们可以使用 `np.fmax` 和 `np.maximum` 函数对两个数组 `x` 和 `y` 进行元素级最大值计算" - ] - }, - { - "cell_type": "code", - "execution_count": 93, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([1., 2., 3., 4.])" - ] - }, - "execution_count": 93, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a1=np.fmax(x,y)\n", - "a1" - ] - }, - { - "cell_type": "code", - "execution_count": 94, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([1., 2., 3., 4.])" - ] - }, - "execution_count": 94, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a2=np.maximum(x,y)\n", - "a2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 2.最小值计算\n", - "我们可以使用 `np.fmin` 和 `np.minimum` 函数对两个数组 `x` 和 `y` 进行元素级最大值计算" - ] - }, - { - "cell_type": "code", - "execution_count": 95, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([-1.2, 1.4, 1.5, 1.7])" - ] - }, - "execution_count": 95, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a1=np.fmin(x,y)\n", - "a1" - ] - }, - { - "cell_type": "code", - "execution_count": 96, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([-1.2, 1.4, 1.5, 1.7])" - ] - }, - "execution_count": 96, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a2=np.minimum(x,y)\n", - "a2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 元素及模运算\n", - "我们可以使用 `np.mod` 函数对两个数组元素进行模运算。" - ] - }, - { - "cell_type": "code", - "execution_count": 97, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([-0.2, 0.6, 0. , 0.6])" - ] - }, - "execution_count": 97, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.mod(x,y)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "除此之外,我们可以使用 `np.copysign` 函数,将数组 `y` 中各元素的符号赋值给数组 `x` 的对应元素。" - ] - }, - { - "cell_type": "code", - "execution_count": 98, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([-1., 2., 3., 4.])" - ] - }, - "execution_count": 98, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.copysign(x,y)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 数组算数比较\n", - "我们可以对两个数组进行算数比较,产生布尔型数组。\n", - "这里我们使用的函数符号有:\n", - "`<` (小于),`>` (大于), `>=` (大于等于), `<=` (小于等于), `==` (等于),`!=` (不等于)。\n", - "需要注意的是,我们常用 `=` 表示赋值功能,因此在判定数组是否相等中,使用 `==` 符号。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "下面用一个例子作为示范,使用 `==` 对数组 `x` , `y` 元素级进行比较是否相等,相等输出结果 `True` ,若元素对应不相等,则输出结果 `False`。" - ] - }, - { - "cell_type": "code", - "execution_count": 99, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([False, False, False, False])" - ] - }, - "execution_count": 99, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x==y" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "由此我们可以知道,对于该两个数组 `x` 和 `y` ,每一个对应元素值都不相等。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 按元素位操作(Elementwise bit operations)\n", - "\n", - "### 按位与(&)\n", - "\n", - "按位与(`&`)运算符是,在两个操作数对应的二进制位都为 `1` 时,该位的结果值才为 `1`,将运算符应用于每对位,然后按位构造结果。\n", - "| a \t| b \t| a AND b|\n", - "|:---:\t|:---:\t|:---:|\n", - "| 0 \t| 0 \t| 0 |\n", - "| 0 \t| 1 | 0 |\n", - "| 1 \t| 0 | 0 |\n", - "| 1 | 1 |1 | \n", - "\n", - "性质:任何数组 `x` 与 `0` 进行按位与运算都会得到数字 `0`。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`bitwise_and` 对两个数组按元素计算按位与(bit-wise AND)。\n", - "让我们通过一个例子实践一下,数字 `9` (十进制)可以用二进制表示为 `0000 1001` 。数字 `23` 同样可以用二进制表示为 `0001 0111`。则 `9` 与`23` 的按位与(bit-wise AND)就是 `0000 0001` ,或者说1。" - ] - }, - { - "cell_type": "code", - "execution_count": 100, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 100, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_and(9,23)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "更进一步,`21` (base 10) = `0001 0101`。\n", - "则 `23` 与`21` 做按位与(bit-wise AND)计算 `0001 0101`, 或者说21." - ] - }, - { - "cell_type": "code", - "execution_count": 101, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "21" - ] - }, - "execution_count": 101, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_and(21,23)" - ] - }, - { - "cell_type": "code", - "execution_count": 102, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'10101'" - ] - }, - "execution_count": 102, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.binary_repr(21) #使用二进制表示" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "接下来,我们可以使用 `bitwise_and` 对数组(array)进行按位与运算,下面是一些例子。" - ] - }, - { - "cell_type": "code", - "execution_count": 103, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 1, 21], dtype=int32)" - ] - }, - "execution_count": 103, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_and([9,21],23)" - ] - }, - { - "cell_type": "code", - "execution_count": 104, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([1, 4])" - ] - }, - "execution_count": 104, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_and([9,21],[23,14])" - ] - }, - { - "cell_type": "code", - "execution_count": 105, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 2, 4, 16])" - ] - }, - "execution_count": 105, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_and(np.array([2,5,255]), np.array([3,14,16]))" - ] - }, - { - "cell_type": "code", - "execution_count": 106, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([False, False])" - ] - }, - "execution_count": 106, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_and([True, False], [False, False])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "在给定数组的情况下,该函数操作可以简化为 `&` :" - ] - }, - { - "cell_type": "code", - "execution_count": 107, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 2, 4, 16])" - ] - }, - "execution_count": 107, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x1 = np.array([2,5,255])\n", - "x2 = np.array([3,14,16])\n", - "x1 & x2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "除了按位与(`&`)外,位操作函数还有:\n", - "`bitwise_or` 或\n", - "`bitwise_xor` 异或" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 按位或(|)\n", - "\n", - "\n", - "| a \t| b \t| a AND b|\n", - "|:---:\t|:---:\t|:---:|\n", - "| 0 \t| 0 \t| 0 |\n", - "| 0 \t| 1 | 1 |\n", - "| 1 \t| 0 | 1 |\n", - "| 1 | 1 | 1 | \n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`bitwise_or` 对两个数组按元素计算按位或(bit-wise OR)。\n", - "让我们通过一个例子实践一下,数字 `9` (十进制)可以用二进制表示为 `0000 1001` 。数字 `23` 同样可以用二进制表示为 `0001 0111`。则 `9` 与`23` 的按位或(bit-wise OR)就是 `0001 1111` ,或者说 `31`。" - ] - }, - { - "cell_type": "code", - "execution_count": 108, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "31" - ] - }, - "execution_count": 108, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_or(9,23)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "接下来,我们可以使用 `bitwise_or` 对数组(array)进行按位与运算,下面是更多的一些例子。" - ] - }, - { - "cell_type": "code", - "execution_count": 109, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([31, 23], dtype=int32)" - ] - }, - "execution_count": 109, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_or([9,21],23)" - ] - }, - { - "cell_type": "code", - "execution_count": 110, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([31, 31])" - ] - }, - "execution_count": 110, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_or([9,21],[23,14])" - ] - }, - { - "cell_type": "code", - "execution_count": 111, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 3, 15, 255])" - ] - }, - "execution_count": 111, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_or(np.array([2,5,255]), np.array([3,14,16]))" - ] - }, - { - "cell_type": "code", - "execution_count": 112, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ True, False])" - ] - }, - "execution_count": 112, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_or([True, False], [False, False])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "在给定数组的情况下,该函数操作可以简化为 `|` :" - ] - }, - { - "cell_type": "code", - "execution_count": 113, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 3, 15, 255])" - ] - }, - "execution_count": 113, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x1 = np.array([2,5,255])\n", - "x2 = np.array([3,14,16])\n", - "x1 | x2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 异或(^)\n", - "| a \t| b \t| a AND b|\n", - "|:---:\t|:---:\t|:---:|\n", - "| 0 \t| 0 \t| 0 |\n", - "| 0 \t| 1 | 1 |\n", - "| 1 \t| 0 | 1 |\n", - "| 1 | 1 | 0 | " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "让我们通过一个例子实践一下,数字 `9` (十进制)可以用二进制表示为 `0000 1001` 。数字 `23` 同样可以用二进制表示为 `0001 0111`。则 `9` 与`23` 的按位或(bit-wise XOR)就是 `0001 1110` ,或者说 `30`。" - ] - }, - { - "cell_type": "code", - "execution_count": 114, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "30" - ] - }, - "execution_count": 114, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_xor(9,23)" - ] - }, - { - "cell_type": "code", - "execution_count": 115, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([30, 27])" - ] - }, - "execution_count": 115, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_xor([9,21], [23,14])" - ] - }, - { - "cell_type": "code", - "execution_count": 116, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ True, False])" - ] - }, - "execution_count": 116, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_xor([True, True], [False, True])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "在给定数组的情况下,该函数操作可以简化为 `^` :" - ] - }, - { - "cell_type": "code", - "execution_count": 117, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 1, 11, 239])" - ] - }, - "execution_count": 117, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x1 = np.array([2,5,255])\n", - "x2 = np.array([3,14,16])\n", - "x1 ^ x2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 按位取否(bit-wise NOT)\n", - "`invert()` 函数计算输入数组中整数的二进制按位取否的结果。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "下面举例来看 `invert()` 函数的作用。\n", - "`18` (base 10) = `0001 0010` (base 2), 那么对 `18` 按位取否(bit-wise NOT)得到:" - ] - }, - { - "cell_type": "code", - "execution_count": 118, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "237" - ] - }, - "execution_count": 118, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x = np.invert(np.array(18, dtype=np.uint8))\n", - "x" - ] - }, - { - "cell_type": "code", - "execution_count": 119, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'11101101'" - ] - }, - "execution_count": 119, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.binary_repr(x, width=8)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "需要注意的是,输出的结果取决于 `bit_width` 。\n", - "接着上面的例子,当 `dtype` 取 `16` 时,结果会变得不同:" - ] - }, - { - "cell_type": "code", - "execution_count": 120, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "65517" - ] - }, - "execution_count": 120, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "y = np.invert(np.array(18, dtype=np.uint16))\n", - "y" - ] - }, - { - "cell_type": "code", - "execution_count": 121, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'1111111111101101'" - ] - }, - "execution_count": 121, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.binary_repr(y, width=16)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "布尔型也可以使用:" - ] - }, - { - "cell_type": "code", - "execution_count": 122, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([False, True])" - ] - }, - "execution_count": 122, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.invert(np.array([True, False]))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "在给定数组的情况下,该函数操作可以简化为 `~` :" - ] - }, - { - "cell_type": "code", - "execution_count": 123, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([253, 250, 247], dtype=uint8)" - ] - }, - "execution_count": 123, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x1 = np.array([2,5,8], dtype=np.uint8)\n", - "~x1" - ] - }, - { - "cell_type": "code", - "execution_count": 124, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([False, True])" - ] - }, - "execution_count": 124, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x2 = np.array([True, False])\n", - "~x2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 移位\n", - "将输入数组的整数按二进制的位向左/向右移位。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 向左移位\n", - "`letf_shift` 将输入数组的整数按二进制的位向左移位。\n", - "具体的操作是,通过在 `x1` 的右边附加 `x2 ` 个 `0` ,从而向左移位。\n", - "由于数字是二进制格式表示,所以该运算等价于 `x1×2^x2` 。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "下面通过举例来看 `left_shift` 具体作用。\n", - "`5` (base 10) = `0101` (base 2):" - ] - }, - { - "cell_type": "code", - "execution_count": 125, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "20" - ] - }, - "execution_count": 125, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.left_shift(5, 2)" - ] - }, - { - "cell_type": "code", - "execution_count": 126, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'10100'" - ] - }, - "execution_count": 126, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.binary_repr(20)" - ] - }, - { - "cell_type": "code", - "execution_count": 127, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([10, 20, 40], dtype=int32)" - ] - }, - "execution_count": 127, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.left_shift(5, [1,2,3])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "需要注意的是,第二个参数的 `dtype` 可能会改变结果的 `dtype`:" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "例如,`255` (base 10) = `1111 1111` (base 2),`254` (base 10) = `1111 1110` (base 2)。\n", - "我们希望将 `255` 向左移动 `1` 位得到 `254` :" - ] - }, - { - "cell_type": "code", - "execution_count": 128, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "510 \n" - ] - } - ], - "source": [ - "a = np.left_shift(np.uint8(255), 1) \n", - "print(a, type(a))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "得到结果510,并不是我们期望的结果,现在我们限定第二个参数的 `dtype`:" - ] - }, - { - "cell_type": "code", - "execution_count": 129, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "254 \n" - ] - } - ], - "source": [ - "b = np.left_shift(np.uint8(255), np.uint8(1))\n", - "print(b, type(b))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "以上便得到了我们所希望移位后得到的结果。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "该函数操作可以简化为 `<<`:" - ] - }, - { - "cell_type": "code", - "execution_count": 130, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([10, 20, 40], dtype=int32)" - ] - }, - "execution_count": 130, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x1 = 5\n", - "x2 = np.array([1, 2, 3])\n", - "x1 << x2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 向右移位\n", - "`right_shift` 将输入数组的整数按二进制的位向左移位。\n", - "具体的操作是,将 `x1` 的向右按位移动 `x2 ` ,从而向右移位。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "下面通过举例来看 `right_shift` 具体作用。\n", - "`10` (base 10) = `1010` (base 2):" - ] - }, - { - "cell_type": "code", - "execution_count": 131, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "5" - ] - }, - "execution_count": 131, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.right_shift(10, 1)" - ] - }, - { - "cell_type": "code", - "execution_count": 132, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'101'" - ] - }, - "execution_count": 132, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.binary_repr(5)" - ] - }, - { - "cell_type": "code", - "execution_count": 133, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([5, 2, 1], dtype=int32)" - ] - }, - "execution_count": 133, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.right_shift(10, [1,2,3])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "该函数操作可以简化为 `>>`:" - ] - }, - { - "cell_type": "code", - "execution_count": 134, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([5, 2, 1], dtype=int32)" - ] - }, - "execution_count": 134, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x1 = 10\n", - "x2 = np.array([1,2,3])\n", - "x1 >> x2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 按位压缩存储(Bit packing)\n", - "\n", - "`packbits()` 函数,将二进制数值数组的元素打包成一个 `unit8` 数组中的位。\n", - "具体操作是通过在数组中的整数末尾插入 `0` ,使输出结果被填充为完整字节。" - ] - }, - { - "cell_type": "code", - "execution_count": 135, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[[160],\n", - " [ 64]],\n", - "\n", - " [[192],\n", - " [ 32]]], dtype=uint8)" - ] - }, - "execution_count": 135, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a = np.array([[[1,0,1],\n", - " [0,1,0]],\n", - " [[1,1,0],\n", - " [0,0,1]]])\n", - "b = np.packbits(a, axis=-1)\n", - "b" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`160` (base 10) = `1010 0000` ;\n", - "`64` (base 10) = `0100 0000` ;\n", - "`192` (base 10) = `1100 0000` ;\n", - "`32` (base 10) = `0010 0000` 。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`unpackbits()` 函数,将 `uint8` 数组的元素解压缩到二进制值的输出数组中。\n", - "\n", - "每个元素都表示一个应解压缩到二进制值输出数组中的位字段。输出数组的形状可以是一维的(如果 `axis=None` ),也可以是与输入数组相同的形状,并沿着指定的轴进行解压。" - ] - }, - { - "cell_type": "code", - "execution_count": 136, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[0, 0, 0, 0, 0, 0, 1, 0],\n", - " [0, 0, 0, 0, 0, 1, 1, 1],\n", - " [0, 0, 0, 1, 0, 1, 1, 1]], dtype=uint8)" - ] - }, - "execution_count": 136, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a = np.array([[2], [7], [23]], dtype=np.uint8)\n", - "b = np.unpackbits(a, axis=1)\n", - "b" - ] - }, - { - "cell_type": "code", - "execution_count": 137, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[0, 0, 0, 0, 0, 0],\n", - " [0, 0, 0, 0, 0, 1],\n", - " [0, 0, 0, 1, 0, 1]], dtype=uint8)" - ] - }, - "execution_count": 137, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "c = np.unpackbits(a, axis=1, count=6)\n", - "c" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 输出格式\n", - "`binary_repr(num, width=None)` 函数用于将输入数组的整数以二进制格式输出。\n" - ] - }, - { - "cell_type": "code", - "execution_count": 138, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'101'" - ] - }, - "execution_count": 138, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.binary_repr(5)" - ] - }, - { - "cell_type": "code", - "execution_count": 139, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'-101'" - ] - }, - "execution_count": 139, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.binary_repr(-5)" - ] - }, - { - "cell_type": "code", - "execution_count": 140, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'00101'" - ] - }, - "execution_count": 140, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.binary_repr(5, width=5)" - ] - }, - { - "cell_type": "code", - "execution_count": 141, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'0101'" - ] - }, - "execution_count": 141, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.binary_repr(5, width=4)" - ] - } - ], - "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.10.11" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/ch-numpy/linalg.ipynb b/ch-numpy/linalg.ipynb deleted file mode 100644 index 4a6c954..0000000 --- a/ch-numpy/linalg.ipynb +++ /dev/null @@ -1,403 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 线性代数" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 矩阵与向量的乘积\n", - "### 点积\n", - "`dot(a,b,out=None)` 计算两个数组的点积:\n", - " 1)如果 `a` 和 `b` 都是一维数组,那么点积即为内积(没有共轭);" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "12" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.dot(3, 4)" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(-12+0j)" - ] - }, - "execution_count": 35, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.dot(3j, 4j)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " 2)如果`a` 和 `b` 都是二维数组,那么使用矩阵乘法 `a @ b` ;" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[4, 1],\n", - " [2, 2]])" - ] - }, - "execution_count": 36, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a = [[1, 0], [0, 1]]\n", - "b = [[4, 1], [2, 2]]\n", - "np.dot(a, b)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " 3)如果`a` 或 `b` 是标量(维数为`0`),那么其点积等价于乘,可以使用 `numpy.multiply(a,b)` 或 `a*b` ;" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[16, 4],\n", - " [ 8, 8]])" - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a = 4\n", - "b = [[4,1],[2,2]]\n", - "np.dot(a,b)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " 4)如果`a` 是一维数组, `b` 是`N`维数组,那么点积是 `a` 与 `b` 的最后一个轴的积的和;" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([54, 66, 78])" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a = [3,4,5]\n", - "b = [[1,2,3],[4,5,6],[7,8,9]]\n", - "np.dot(a,b)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " 5)如果`a` 是`N`维数组, `b` 是`M-d`维数组(M≥2),那么点积为 `a` 的最后一个轴与 `b` 的倒数第二条轴的乘机的和:\n", - " `dot(a,b)[i,j,k,m] = sum(a[i,j,:]*b[k,:,m])`" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[ 70, 83, 96],\n", - " [ 60, 72, 84],\n", - " [ 90, 108, 126],\n", - " [106, 128, 150]])" - ] - }, - "execution_count": 39, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a = [[1,5,7],[2,4,6],[3,6,9],[4,8,10]]\n", - "b = [[1,2,3],[4,5,6],[7,8,9]]\n", - "np.dot(a,b)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`linalg.multi_dot(arrays, *, out=None)`函数,在单个函数调用中计算两个或多个数组的点积,同时自动选择最快的求值顺序。\n", - "使用该函数时需要注意的是,如果第一个参数是一维数组,它被视为行向量。如果最后一个参数是一维数组,则将其视为列向量。\n", - "其他参数必须是二维的。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "下面我们通过一个例子学习使用 `linalg.multi_dot(arrays, *, out=None)` 函数:" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [], - "source": [ - "from numpy.linalg import multi_dot" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": {}, - "outputs": [], - "source": [ - "A = np.random.random((10000, 100))\n", - "B = np.random.random((100, 1000))\n", - "C = np.random.random((1000, 5))\n", - "D = np.random.random((5, 333))" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[29258.56199495, 39185.76250743, 24831.33335922, ...,\n", - " 32218.47313706, 49684.46713456, 22935.23821755],\n", - " [27709.83193917, 37113.69763102, 23518.20177806, ...,\n", - " 30512.01252248, 47060.32181675, 21714.06820096],\n", - " [30923.66123875, 41400.43468792, 26235.57546294, ...,\n", - " 34030.73408076, 52492.73599524, 24230.36608396],\n", - " ...,\n", - " [30037.91721463, 40225.74401239, 25493.36791348, ...,\n", - " 33065.16482832, 51002.93827961, 23539.62618817],\n", - " [32787.66087443, 43892.23116514, 27817.26221112, ...,\n", - " 36072.93205314, 55650.19508135, 25687.60971541],\n", - " [32347.16027985, 43328.5110721 , 27457.63882012, ...,\n", - " 35623.51338682, 54936.40902548, 25354.31087954]])" - ] - }, - "execution_count": 42, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "_ = multi_dot([A, B, C, D])\n", - "_" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "我们也可以使用 `vdot(a,b,/)` 函数,返回两个向量的点积。\n", - "需要注意的是,`vdot` 处理多维数组的方式与 `dot` 不同:`vdot`不执行矩阵乘积,而是首先将输入参数扁平化为一维向量。\n", - "因此,`vdot`只能用于向量。" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(70-8j)" - ] - }, - "execution_count": 43, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a = np.array([1+2j,3+4j])\n", - "b = np.array([5+6j,7+8j])\n", - "np.vdot(a, b)" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(70+8j)" - ] - }, - "execution_count": 44, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.vdot(b, a)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "当 `a` 和 `b` 是更高维度的数组时,输出结果依旧是扁平化的一维向量:" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "70" - ] - }, - "execution_count": 45, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a = np.array([[1, 2], [3, 4]])\n", - "b = np.array([[5, 6], [7, 8]])\n", - "np.vdot(a, b)" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "70" - ] - }, - "execution_count": 46, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.vdot(b, a)" - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "70" - ] - }, - "execution_count": 47, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "1*5 + 2*6 + 3*7 + 4*8" - ] - } - ], - "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.10.11" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/ch-numpy/ops.ipynb b/ch-numpy/ops.ipynb index 070ff4c..0bc73e3 100644 --- a/ch-numpy/ops.ipynb +++ b/ch-numpy/ops.ipynb @@ -4,20 +4,24 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# 矩阵运算" + "# 数学运算" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "本章将对创建的高维数组(矩阵)进行一些常规的数学操作,例如一元函数、二元函数以及线性代数。" + "本节将对创建的高维数组进行一些数学运算,包括一元函数、二元函数、统计函数以及线性代数。这些运算操作大部分都比较直观,通过函数名或数学运算符的名字,我们就可以知道其要进行的数学计算。" ] }, { "cell_type": "code", - "execution_count": 1, - "metadata": {}, + "execution_count": 60, + "metadata": { + "tags": [ + "hide-cell" + ] + }, "outputs": [], "source": [ "import numpy as np" @@ -32,65 +36,13 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 61, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([1, 2, 3, 4])" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "x = np.array([1,2,3,4])\n", - "x" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([-1.2, 1.4, 1.5, 1.7])" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ "y = np.array([-1.2,1.4,1.5,1.7])\n", - "y" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([-1.2, 1.4, 1.5, 1.7])" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "z = np.array([-1.2,1.4,1.5,1.7])\n", - "z" + "z = np.array([-1.2,1.4,1.5,1.7])" ] }, { @@ -98,2048 +50,321 @@ "metadata": {}, "source": [ "## 一元函数\n", - "对一个数组执行元素级运算。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 绝对值计算\n", - "下面,我们将对数组中各元素进行绝对值的计算。" + "\n", + "一元函数对一个数组执行元素级运算。下面以对数 $\\log$ 和取整两个计算来演示 NumPy 的一元运算,其他运算可参考其官方文档。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "我们可以使用 `np.abs()` 和 `np.fabs()` 函数进行数组元素的绝对值计算,其中,使用 \n", - "`np.fabs()` 函数时,计算元绝对值时,元素类型为 `float` 。" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([1, 2, 3, 4])" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.abs(x)" + "### 对数\n", + "\n", + "对数函数是数学中的一种常见函数,如果 $a^x=N$,那么 $x = \\log_{a} N$,其中 $a$叫做底数,$N$ 叫真数。通常以 `10` 为底的对数叫做常用对数,以 $e$ 为底的对数称为自然对数。\n", + "\n", + "`np.log()` 是以 $e$ 为底的自然对数。" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 62, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "array([1., 2., 3., 4.])" + "array([0. , 0.69314718, 1.09861229, 1.38629436])" ] }, - "execution_count": 6, + "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "np.fabs(x)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 指数运算" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 1.计算平方根\n", - "我们可以使用 `np.sqrt()` 函数对数组进行元素级开方运算。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "```{note}\n", - "开方运算要求根号下元素非负.\n", - "```" + "np.log(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "由于元素非负性的要求,我们使用数组 `y` 用于练习。" + "`np.log10()` 对数组中元素求常用对数。" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 63, "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Users\\TNT\\AppData\\Local\\Temp\\ipykernel_26416\\3801561550.py:1: RuntimeWarning: invalid value encountered in sqrt\n", - " np.sqrt(y)\n" - ] - }, { "data": { "text/plain": [ - "array([ nan, 1.18321596, 1.22474487, 1.30384048])" + "array([0. , 0.30103 , 0.47712125, 0.60205999])" ] }, - "execution_count": 7, + "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "np.sqrt(y)" + "np.log10(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "#### 2.平方运算\n", - "我们可以使用 `np.square()` 函数对数组中各元素进行平方运算。" + "### 取整运算\n", + "\n", + "`np.ceil()` 对数组各元素向上取整;`np.floor()` 对数组中各个元素向下取整;`np.rint()` 对数组各元素四舍五入取整。" ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "array([ 1, 4, 9, 16])" + "array([-2., 1., 1., 1.])" ] }, - "execution_count": 8, + "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "np.square(x)" - ] - }, - { - "attachments": { - "image.png": { - "image/png": "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" - } - }, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 3.对数运算\n", - "对数函数是数学中的一种常见函数,如果 `a^x=N` ( `a` > `0` ,且 `a` ≠ `1` ),则 `x` 叫做以 `a` 为底 `N` 的对数,记做 `x=logaN` ,其中 `a` 要写于 `log` 右下。\n", - "其中 `a` 叫做对数的底, `N` 叫做真数。\n", - "![image.png](attachment:image.png)\n", - "通常以 `10` 为底的对数叫做常用对数,以 `e` 为底的对数称为自然对数。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### (1)自然对数\n", - "以 `e` 为底的对数称为自然对数。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " \n", - " ```{note}\n", - " `e` 是自然常数,是一个无限不循环小数,且为超越数,其值约为 `2.718281828459045` 。\n", - " ```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "我们可以使用 `np.log()` 函数对数组中元素求自然对数。\n", - "由于数组 `x` 中含有负数元素,而对数要求真数为正,因此,我们使用数组 `y` 进行实践。" + "np.floor(z)" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 65, "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Users\\TNT\\AppData\\Local\\Temp\\ipykernel_26416\\3455148303.py:1: RuntimeWarning: invalid value encountered in log\n", - " np.log(y)\n" - ] - }, { "data": { "text/plain": [ - "array([ nan, 0.33647224, 0.40546511, 0.53062825])" + "array([-1., 1., 2., 2.])" ] }, - "execution_count": 9, + "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "np.log(y)" + "np.rint(z)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "##### (2) 常用对数\n", - "通常以 `10` 为底的对数叫做常用对数。" + "除去以上一元函数,还有以下函数较为常用:\n", + "\n", + "|类型| 函数 | 用途 |\n", + "|:---:|:---:|:---|\n", + "|普通型三角函数|[`np.sin()` ]|计算正弦函数|\n", + "|普通型三角函数|[`np.cos()` ]|计算余弦函数|\n", + "|普通型三角函数|[`np.tan()` ]|计算正切函数|\n", + "|双曲型三角函数|[`np.sinh()` ]|计算双曲正弦函数|\n", + "|双曲型三角函数|[`np.cosh()` ]|计算双曲余弦函数|\n", + "|双曲型三角函数|[`np.tanh()` ]|计算双曲正切函数|\n", + "|指数函数|[`np.exp()` ]|计算数组各元素的指数值|\n", + "|符号函数|[`np.sign()` ]|计算数组各元素的符号值|" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "我们可以使用 `np.log10()` 函数对数组中元素求自然对数。\n", - "由于数组 `x` 中含有负数元素,而对数要求真数为正,因此,我们使用数组 `y` 进行实践。" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Users\\TNT\\AppData\\Local\\Temp\\ipykernel_26416\\4048949146.py:1: RuntimeWarning: invalid value encountered in log10\n", - " np.log10(y)\n" - ] - }, - { - "data": { - "text/plain": [ - "array([ nan, 0.14612804, 0.17609126, 0.23044892])" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.log10(y)" + "## 二元函数" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "##### (3)以2为底的对数" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Users\\TNT\\AppData\\Local\\Temp\\ipykernel_26416\\3578401648.py:1: RuntimeWarning: invalid value encountered in log2\n", - " np.log2(y)\n" - ] - }, - { - "data": { - "text/plain": [ - "array([ nan, 0.48542683, 0.5849625 , 0.76553475])" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.log2(y)" + "二元运算是指对两个对象(操作数)进行的运算:给定集合 $A$,二元函数 $F$ : $A\\times A$ → $A$ 称为集合 $A$ 上的二元运算。需要注意的是,二元运算的运算结果跟两个输入值必须是同种类型的数据。例如,加法的两个操作数都是整数,得到的运算结果也是整数。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "#### 4.取整运算" + "### 简单数学操作" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "##### (1)向上舍入\n", - "我们可以使用 `np.ceil()` 函数计算数组各元素的 `ceiling` 值,即每个元素向上舍入" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([-1., 2., 2., 2.])" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.ceil(z)" + "两个数组的元素加减乘比较直观,使用常用的数学符号即可。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "##### (2)向下舍入\n", - "我们可以使用 `np.floor()` 函数计算数组各元素的 `floor` 值,即每个元素向下舍入。" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([-2., 1., 1., 1.])" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.floor(z)" + "|函数|含义|示例|\n", + "|:---:|:---:|:---|\n", + "|[`+`]|对两个数组进行加法运算|x+y|\n", + "|[`-`]|对两个数组进行减法运算|x-y|\n", + "|[`*`]|对两个数组进行乘法运算|x*y|\n", + "|[`/`]|对两个数组进行乘法运算|x/y|" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "##### (3)四舍五入\n", - "我们可以使用 `np.rint()` 函数计算数组各元素的四舍五入值。" + "下面我们以两个数组元素的加法运算为例:" ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "array([-1., 1., 2., 2.])" + "array([-0.83333333, 1.42857143, 2. , 2.35294118])" ] }, - "execution_count": 14, + "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "np.rint(z)" + "x / y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "我们可以使用 `np.modf()` 函数将数组各元素的小数和整数部分以两个独立数组形式返回。" + "`np.fmax`、`np.maximum` 和 `np.fmin`、`np.minimum`函数对两个数组进行元素级最大/小值计算。" ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "(array([-0.2, 0.4, 0.5, 0.7]), array([-1., 1., 1., 1.]))" + "array([1., 2., 3., 4.])" ] }, - "execution_count": 15, + "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "np.modf(z)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "除去以上常用的 `NumPy` 库中的一元函数,还有以下函数较为常用:\n", - "|类型| 函数 | 用途 |\n", - "|:---:|:---:|:---|\n", - "|普通型三角函数|[`np.sin()` ]|计算正弦函数|\n", - "|普通型三角函数|[`np.cos()` ]|计算余弦函数|\n", - "|普通型三角函数|[`np.tan()` ]|计算正切函数|\n", - "|双曲型三角函数|[`np.sinh()` ]|计算双曲正弦函数|\n", - "|双曲型三角函数|[`np.cosh()` ]|计算双曲余弦函数|\n", - "|双曲型三角函数|[`np.tanh()` ]|计算双曲正切函数|\n", - "|指数函数|[`np.exp()` ]|计算数组各元素的指数值|\n", - "|符号函数|[`np.sign()` ]|计算数组各元素的符号值|" + "np.maximum(x,y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## 二元函数" + "### 比较操作\n", + "\n", + "我们可以对两个数组逐元素进行算数比较,产生布尔型数组:\n", + "\n", + "|符号|含义|\n", + "|:---:|:---|\n", + "|[`<` ]|小于|\n", + "|[`>`]|大于|\n", + "|[`>=`]|大于等于|\n", + "|[ `<=`]|小于等于|\n", + "|[`==` ]|等于|\n", + "|[`!=` ]|不等于|\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "二元运算是指作用于两个对象(例如数组)进行的运算:\n", - "给定集合 `A` ,二元函数 `F` : $A\\times A$ → $A$ 称为集合 `A` 上的二元运算。\n", - "需要注意的是,二元运算的运算结果跟两个输入值必须是同种东西。例如,整数的加法是二元运算,因为整数相加后仍然是整数。" + "```{note}\n", + "需要注意的是,我们常用 `=` 表示赋值功能,不能用来进行数组的比较。判定数组是否相等时,使用 `==` 符号。\n", + "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### 1.简单操作\n", - "将两个数组各元素进行对应运算" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### (1)基础运算\n", - "对于两个数组的元素对应进行加减乘运算。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "|函数|含义|示例|\n", - "|:---:|:---:|:---|\n", - "|[`+`]|对两个数组进行加法运算|x+y|\n", - "|[`-`]|对两个数组进行减法运算|x-y|\n", - "|[`*`]|对两个数组进行乘法运算|x*y|" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "下面我们以两个数组元素的加法运算为例:" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([-0.2, 3.4, 4.5, 5.7])" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x+y" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### (2)最值计算\n", - "对两个数组间进行元素级最值计算" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### 1)最大值计算\n", - "我们可以使用 `np.fmax` 和 `np.maximum` 函数对两个数组 `x` 和 `y` 进行元素级最大值计算" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([1., 2., 3., 4.])" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a1=np.fmax(x,y)\n", - "a1" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([1., 2., 3., 4.])" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a2=np.maximum(x,y)\n", - "a2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### 2)最小值计算\n", - "同样地,我们可以使用 `np.fmin` 和 `np.minimum` 函数对两个数组 `x` 和 `y` 进行元素级最大值计算" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### (2)元素及模运算\n", - "我们可以使用 `np.mod` 函数对两个数组元素进行模运算。" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([-0.2, 0.6, 0. , 0.6])" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.mod(x,y)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "除此之外,我们可以使用 `np.copysign` 函数,将数组 `y` 中各元素的符号赋值给数组 `x` 的对应元素。" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([-1., 2., 3., 4.])" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.copysign(x,y)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### (3)数组算数比较\n", - "我们可以对两个数组进行算数比较,产生布尔型数组。\n", - "这里我们使用的函数符号有:\n", - "|符号|含义|\n", - "|:---:|:---|\n", - "|[`<` ]|小于|\n", - "|[`>`]|大于|\n", - "|[`>=`]|大于等于|\n", - "|[ `<=`]|小于等于|\n", - "|[`==` ]|等于|\n", - "|[`!=` ]|不等于|\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "```{note}\n", - "需要注意的是,我们常用 `=` 表示赋值功能,因此在判定数组是否相等中,使用 `==` 符号。\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "下面用一个例子作为示范,使用 `==` 对数组 `x` , `y` 元素级进行比较是否相等,相等输出结果 `True` ,若元素对应不相等,则输出结果 `False`。" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([False, False, False, False])" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x==y" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "由此我们可以知道,对于该两个数组 `x` 和 `y` ,每一个对应元素值都不相等。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2.按元素位操作(Elementwise bit operations)\n", - "\n", - "#### (1)按位与(&)\n", - "\n", - "按位与(`&`)运算符是,在两个操作数对应的二进制位都为 `1` 时,该位的结果值才为 `1`,将运算符应用于每对位,然后按位构造结果。\n", - "| a \t| b \t| a AND b|\n", - "|:---:\t|:---:\t|:---:|\n", - "| 0 \t| 0 \t| 0 |\n", - "| 0 \t| 1 | 0 |\n", - "| 1 \t| 0 | 0 |\n", - "| 1 | 1 |1 | \n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "```{note}\n", - "性质:任何数组 x 与 0 进行按位与运算都会得到数字 0。\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`bitwise_and` 对两个数组按元素计算按位与(bit-wise AND)。\n", - "让我们通过一个例子实践一下,数字 `9` (十进制)可以用二进制表示为 `0000 1001` 。数字 `23` 同样可以用二进制表示为 `0001 0111`。则 `9` 与`23` 的按位与(bit-wise AND)就是 `0000 0001` ,或者说1。" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_and(9,23)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "更进一步,`21` (base 10) = `0001 0101`。\n", - "则 `23` 与`21` 做按位与(bit-wise AND)计算 `0001 0101`, 或者说21." - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "21" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_and(21,23)" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'10101'" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.binary_repr(21) #使用二进制表示" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "接下来,我们可以使用 `bitwise_and` 对数组(array)进行按位与运算,下面是一些例子。" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 1, 21], dtype=int32)" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_and([9,21],23)" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 2, 4, 16])" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_and(np.array([2,5,255]), np.array([3,14,16]))" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([False, False])" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_and([True, False], [False, False])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "在给定数组的情况下,该函数操作可以简化为 `&` :" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 2, 4, 16])" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x1 = np.array([2,5,255])\n", - "x2 = np.array([3,14,16])\n", - "x1 & x2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "除了按位与(`&`)外,位操作函数还有:\n", - "`bitwise_or` 或\n", - "`bitwise_xor` 异或" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### (2)按位或(|)\n", - "\n", - "\n", - "| a \t| b \t| a AND b|\n", - "|:---:\t|:---:\t|:---:|\n", - "| 0 \t| 0 \t| 0 |\n", - "| 0 \t| 1 | 1 |\n", - "| 1 \t| 0 | 1 |\n", - "| 1 | 1 | 1 | \n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`bitwise_or` 对两个数组按元素计算按位或(bit-wise OR)。\n", - "让我们通过一个例子实践一下,数字 `9` (十进制)可以用二进制表示为 `0000 1001` 。数字 `23` 同样可以用二进制表示为 `0001 0111`。则 `9` 与`23` 的按位或(bit-wise OR)就是 `0001 1111` ,或者说 `31`。" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "31" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_or(9,23)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "接下来,我们可以使用 `bitwise_or` 对数组(array)进行按位与运算,下面是更多的一些例子。" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([31, 23], dtype=int32)" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_or([9,21],23)" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 3, 15, 255])" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_or(np.array([2,5,255]), np.array([3,14,16]))" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ True, False])" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_or([True, False], [False, False])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "在给定数组的情况下,该函数操作可以简化为 `|` :" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 3, 15, 255])" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x1 = np.array([2,5,255])\n", - "x2 = np.array([3,14,16])\n", - "x1 | x2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### (3)异或(^)\n", - "| a \t| b \t| a AND b|\n", - "|:---:\t|:---:\t|:---:|\n", - "| 0 \t| 0 \t| 0 |\n", - "| 0 \t| 1 | 1 |\n", - "| 1 \t| 0 | 1 |\n", - "| 1 | 1 | 0 | " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "让我们通过一个例子实践一下,数字 `9` (十进制)可以用二进制表示为 `0000 1001` 。数字 `23` 同样可以用二进制表示为 `0001 0111`。则 `9` 与`23` 的按位或(bit-wise XOR)就是 `0001 1110` ,或者说 `30`。" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "30" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_xor(9,23)" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([30, 27])" - ] - }, - "execution_count": 35, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_xor([9,21], [23,14])" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ True, False])" - ] - }, - "execution_count": 36, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.bitwise_xor([True, True], [False, True])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "在给定数组的情况下,该函数操作可以简化为 `^` :" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 1, 11, 239])" - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x1 = np.array([2,5,255])\n", - "x2 = np.array([3,14,16])\n", - "x1 ^ x2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### (4)按位取否(bit-wise NOT)\n", - "`invert()` 函数计算输入数组中整数的二进制按位取否的结果。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "下面举例来看 `invert()` 函数的作用。\n", - "`18` (base 10) = `0001 0010` (base 2), 那么对 `18` 按位取否(bit-wise NOT)得到:" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "237" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x = np.invert(np.array(18, dtype=np.uint8))\n", - "x" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'11101101'" - ] - }, - "execution_count": 39, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.binary_repr(x, width=8)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "需要注意的是,输出的结果取决于 `bit_width` 。\n", - "接着上面的例子,当 `dtype` 取 `16` 时,结果会变得不同:" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "65517" - ] - }, - "execution_count": 40, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "y = np.invert(np.array(18, dtype=np.uint16))\n", - "y" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'1111111111101101'" - ] - }, - "execution_count": 41, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.binary_repr(y, width=16)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "布尔型也可以使用:" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([False, True])" - ] - }, - "execution_count": 42, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.invert(np.array([True, False]))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "在给定数组的情况下,该函数操作可以简化为 `~` :" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([253, 250, 247], dtype=uint8)" - ] - }, - "execution_count": 43, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x1 = np.array([2,5,8], dtype=np.uint8)\n", - "~x1" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([False, True])" - ] - }, - "execution_count": 44, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x2 = np.array([True, False])\n", - "~x2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### (5)移位\n", - "将输入数组的整数按二进制的位向左/向右移位。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### 1)向左移位\n", - "`letf_shift` 将输入数组的整数按二进制的位向左移位。\n", - "具体的操作是,通过在 `x1` 的右边附加 `x2 ` 个 `0` ,从而向左移位。\n", - "由于数字是二进制格式表示,所以该运算等价于 `x1×2^x2` 。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "下面通过举例来看 `left_shift` 具体作用。\n", - "`5` (base 10) = `0101` (base 2):" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "20" - ] - }, - "execution_count": 45, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.left_shift(5, 2)" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'10100'" - ] - }, - "execution_count": 46, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.binary_repr(20)" - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([10, 20, 40], dtype=int32)" - ] - }, - "execution_count": 47, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.left_shift(5, [1,2,3])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "需要注意的是,第二个参数的 `dtype` 可能会改变结果的 `dtype`:" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "例如,`255` (base 10) = `1111 1111` (base 2),`254` (base 10) = `1111 1110` (base 2)。\n", - "我们希望将 `255` 向左移动 `1` 位得到 `254` :" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "510 \n" - ] - } - ], - "source": [ - "a = np.left_shift(np.uint8(255), 1) \n", - "print(a, type(a))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "得到结果 `510` ,并不是我们期望的结果,现在我们限定第二个参数的 `dtype`:" - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "254 \n" - ] - } - ], - "source": [ - "b = np.left_shift(np.uint8(255), np.uint8(1))\n", - "print(b, type(b))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "以上便得到了我们所希望移位后得到的结果。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "该函数操作可以简化为 `<<`:" - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([10, 20, 40], dtype=int32)" - ] - }, - "execution_count": 50, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x1 = 5\n", - "x2 = np.array([1, 2, 3])\n", - "x1 << x2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### 2)向右移位\n", - "`right_shift` 将输入数组的整数按二进制的位向左移位。\n", - "具体的操作是,将 `x1` 的向右按位移动 `x2 ` ,从而向右移位。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "下面通过举例来看 `right_shift` 具体作用。\n", - "`10` (base 10) = `1010` (base 2):" - ] - }, - { - "cell_type": "code", - "execution_count": 51, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "5" - ] - }, - "execution_count": 51, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.right_shift(10, 1)" - ] - }, - { - "cell_type": "code", - "execution_count": 52, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'101'" - ] - }, - "execution_count": 52, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.binary_repr(5)" - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([5, 2, 1], dtype=int32)" - ] - }, - "execution_count": 53, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.right_shift(10, [1,2,3])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "该函数操作可以简化为 `>>`:" - ] - }, - { - "cell_type": "code", - "execution_count": 54, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([5, 2, 1], dtype=int32)" - ] - }, - "execution_count": 54, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x1 = 10\n", - "x2 = np.array([1,2,3])\n", - "x1 >> x2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 3.按位压缩存储(Bit packing)\n", - "\n", - "`packbits()` 函数,将二进制数值数组的元素打包成一个 `unit8` 数组中的位。\n", - "具体操作是通过在数组中的整数末尾插入 `0` ,使输出结果被填充为完整字节。" - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[[160],\n", - " [ 64]],\n", - "\n", - " [[192],\n", - " [ 32]]], dtype=uint8)" - ] - }, - "execution_count": 55, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a = np.array([[[1,0,1],\n", - " [0,1,0]],\n", - " [[1,1,0],\n", - " [0,0,1]]])\n", - "b = np.packbits(a, axis=-1)\n", - "b" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`160` (base 10) = `1010 0000` ;\n", - "`64` (base 10) = `0100 0000` ;\n", - "`192` (base 10) = `1100 0000` ;\n", - "`32` (base 10) = `0010 0000` 。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`unpackbits()` 函数,将 `uint8` 数组的元素解压缩到二进制值的输出数组中。\n", - "\n", - "每个元素都表示一个应解压缩到二进制值输出数组中的位字段。输出数组的形状可以是一维的(如果 `axis=None` ),也可以是与输入数组相同的形状,并沿着指定的轴进行解压。" - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[0, 0, 0, 0, 0, 0, 1, 0],\n", - " [0, 0, 0, 0, 0, 1, 1, 1],\n", - " [0, 0, 0, 1, 0, 1, 1, 1]], dtype=uint8)" - ] - }, - "execution_count": 56, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a = np.array([[2], [7], [23]], dtype=np.uint8)\n", - "b = np.unpackbits(a, axis=1)\n", - "b" - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[0, 0, 0, 0, 0, 0],\n", - " [0, 0, 0, 0, 0, 1],\n", - " [0, 0, 0, 1, 0, 1]], dtype=uint8)" - ] - }, - "execution_count": 57, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "c = np.unpackbits(a, axis=1, count=6)\n", - "c" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 4.输出格式\n", - "`binary_repr(num, width=None)` 函数用于将输入数组的整数以二进制格式输出。" - ] - }, - { - "cell_type": "code", - "execution_count": 58, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'101'" - ] - }, - "execution_count": 58, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.binary_repr(5)" - ] - }, - { - "cell_type": "code", - "execution_count": 59, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'-101'" - ] - }, - "execution_count": 59, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.binary_repr(-5)" - ] - }, - { - "cell_type": "code", - "execution_count": 60, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'00101'" - ] - }, - "execution_count": 60, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.binary_repr(5, width=5)" - ] - }, - { - "cell_type": "code", - "execution_count": 61, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'0101'" - ] - }, - "execution_count": 61, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.binary_repr(5, width=4)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 统计函数\n", - "不同于一元函数和二元函数,对数组进行元素级运算,统计函数对一个数组行、列及整体运算。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "```{note}\n", - "axis=0/1 ,该参数不指定时默认求整体;axis=0 对列计算; axis=1 对行计算 (下面不再演示)。\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "|函数|用途|\n", - "|:---:|:---|\n", - "|[`_.mean()`]|对数组整体求平均值|\n", - "|[`_.sum()`]|数组求和|\n", - "|[`_.max()`]|求数组中最大值|\n", - "|[`_.min()`]|求数组中最小值|\n", - "|[`_.var()`]|数组整体求方差(默认情况下,对数组整体求解)|\n", - "|[`_.np.std()`]|对数组整体求标准误|" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 线性代数" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 1.矩阵与向量的乘积\n", - "#### 点积\n", - "`dot(a,b,out=None)` 计算两个数组的点积:\n", - " 1)如果 `a` 和 `b` 都是一维数组,那么点积即为内积(没有共轭);" - ] - }, - { - "cell_type": "code", - "execution_count": 62, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "12" - ] - }, - "execution_count": 62, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.dot(3, 4)" - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(-12+0j)" - ] - }, - "execution_count": 63, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.dot(3j, 4j)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " 2)如果`a` 和 `b` 都是二维数组,那么使用矩阵乘法 `a @ b` ;" - ] - }, - { - "cell_type": "code", - "execution_count": 64, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[4, 1],\n", - " [2, 2]])" - ] - }, - "execution_count": 64, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a = [[1, 0], [0, 1]]\n", - "b = [[4, 1], [2, 2]]\n", - "np.dot(a, b)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " 3)如果`a` 或 `b` 是标量(维数为`0`),那么其点积等价于乘,可以使用 `numpy.multiply(a,b)` 或 `a*b` ;" - ] - }, - { - "cell_type": "code", - "execution_count": 65, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[16, 4],\n", - " [ 8, 8]])" - ] - }, - "execution_count": 65, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a = 4\n", - "b = [[4,1],[2,2]]\n", - "np.dot(a,b)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " 4)如果`a` 是一维数组, `b` 是`N`维数组,那么点积是 `a` 与 `b` 的最后一个轴的积的和;" - ] - }, - { - "cell_type": "code", - "execution_count": 66, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([54, 66, 78])" - ] - }, - "execution_count": 66, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a = [3,4,5]\n", - "b = [[1,2,3],[4,5,6],[7,8,9]]\n", - "np.dot(a,b)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " 5)如果`a` 是`N`维数组, `b` 是`M-d`维数组(M≥2),那么点积为 `a` 的最后一个轴与 `b` 的倒数第二条轴的乘机的和:\n", - " `dot(a,b)[i,j,k,m] = sum(a[i,j,:]*b[k,:,m])`" + "下面用一个例子作为示范,使用 `==` 对数组 `x` , `y` 元素级进行比较是否相等,相等输出结果 `True` ,若元素对应不相等,则输出结果 `False`。" ] }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 68, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "array([[ 70, 83, 96],\n", - " [ 60, 72, 84],\n", - " [ 90, 108, 126],\n", - " [106, 128, 150]])" + "array([False, False, False, False])" ] }, - "execution_count": 67, + "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "a = [[1,5,7],[2,4,6],[3,6,9],[4,8,10]]\n", - "b = [[1,2,3],[4,5,6],[7,8,9]]\n", - "np.dot(a,b)" + "x==y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "`linalg.multi_dot(arrays, *, out=None)`函数,在单个函数调用中计算两个或多个数组的点积,同时自动选择最快的求值顺序。\n", - "使用该函数时需要注意的是,如果第一个参数是一维数组,它被视为行向量。如果最后一个参数是一维数组,则将其视为列向量。\n", - "其他参数必须是二维的。" + "## 统计函数\n", + "\n", + "一元函数和二元函数对数组进行元素级运算,统计函数对高维数组的某个维度(行或列)及整体进行统计运算。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "下面我们通过一个例子学习使用 `linalg.multi_dot(arrays, *, out=None)` 函数:" - ] - }, - { - "cell_type": "code", - "execution_count": 68, - "metadata": {}, - "outputs": [], - "source": [ - "from numpy.linalg import multi_dot" + "```{note}\n", + "`axis` 参数用来指定对高维数组的哪个维度(或者说是轴)进行操作,不指定时默认求整体;`axis=0` 对高维数组的第一个维度进行计算,二维数组的 `axis=0` 指的是列; `axis=1` 对高维数组的第二个维度进行计算,二维数组的 `axis=1` 指的是行。\n", + "```" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "array([[0, 1, 2],\n", + " [3, 4, 5]])" + ] + }, + "execution_count": 69, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "A = np.random.random((10000, 100))\n", - "B = np.random.random((100, 1000))\n", - "C = np.random.random((1000, 5))\n", - "D = np.random.random((5, 333))" + "np_array_2d = np.arange(0, 6).reshape([2,3])\n", + "np_array_2d" ] }, { @@ -2150,19 +375,7 @@ { "data": { "text/plain": [ - "array([[35131.61158413, 18613.23337998, 29691.28900539, ...,\n", - " 43075.11560213, 40250.13158911, 39312.73602514],\n", - " [36036.48526667, 19110.88903417, 30466.94168399, ...,\n", - " 44205.74956408, 41292.42642951, 40333.49163259],\n", - " [34243.44514877, 18141.41363515, 28936.18893771, ...,\n", - " 41983.05410692, 39230.89345756, 38314.28093744],\n", - " ...,\n", - " [37884.92498048, 20081.63437724, 32022.58975952, ...,\n", - " 46459.14260604, 43406.86342706, 42398.11184878],\n", - " [40065.5968624 , 21243.13668627, 33867.12057961, ...,\n", - " 49142.06395326, 45907.32213681, 44839.35873359],\n", - " [35720.22531001, 18934.20066418, 30191.67932084, ...,\n", - " 43809.94871673, 40930.89160805, 39985.77263399]])" + "array([3, 5, 7])" ] }, "execution_count": 70, @@ -2171,17 +384,7 @@ } ], "source": [ - "_ = multi_dot([A, B, C, D])\n", - "_" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "我们也可以使用 `vdot(a,b,/)` 函数,返回两个向量的点积。\n", - "需要注意的是,`vdot` 处理多维数组的方式与 `dot` 不同:`vdot`不执行矩阵乘积,而是首先将输入参数扁平化为一维向量。\n", - "因此,`vdot`只能用于向量。" + "np.sum(np_array_2d, axis = 0)" ] }, { @@ -2192,7 +395,7 @@ { "data": { "text/plain": [ - "(70-8j)" + "15" ] }, "execution_count": 71, @@ -2201,9 +404,46 @@ } ], "source": [ - "a = np.array([1+2j,3+4j])\n", - "b = np.array([5+6j,7+8j])\n", - "np.vdot(a, b)" + "np.sum(np_array_2d)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "其他统计函数还有:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "|函数|用途|\n", + "|:---:|:---|\n", + "|[`np.mean()`]|求平均值|\n", + "|[`np.sum()`]|求和|\n", + "|[`np.max()`]|求最大值|\n", + "|[`np.min()`]|求最小值|\n", + "|[`np.var()`]|求方差|\n", + "|[`np.std()`]|求标准误|" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 线性代数" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 矩阵与向量的乘积\n", + "\n", + "`dot(a,b)` 计算两个数组的点积:\n", + "\n", + "1)如果 `a` 和 `b` 都是一维数组,那么点积即为内积(没有共轭);" ] }, { @@ -2214,7 +454,7 @@ { "data": { "text/plain": [ - "(70+8j)" + "12" ] }, "execution_count": 72, @@ -2223,14 +463,7 @@ } ], "source": [ - "np.vdot(b, a)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "当 `a` 和 `b` 是更高维度的数组时,输出结果依旧是扁平化的一维向量:" + "np.dot(3, 4)" ] }, { @@ -2241,7 +474,7 @@ { "data": { "text/plain": [ - "70" + "(-12+0j)" ] }, "execution_count": 73, @@ -2250,9 +483,14 @@ } ], "source": [ - "a = np.array([[1, 2], [3, 4]])\n", - "b = np.array([[5, 6], [7, 8]])\n", - "np.vdot(a, b)" + "np.dot(3j, 4j)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " 2)如果 `a` 和 `b` 都是二维数组,`np.dot()` 等价于矩阵乘法,也可以用 `a @ b` 来表示;" ] }, { @@ -2263,7 +501,8 @@ { "data": { "text/plain": [ - "70" + "array([[4, 1],\n", + " [2, 2]])" ] }, "execution_count": 74, @@ -2272,7 +511,16 @@ } ], "source": [ - "np.vdot(b, a)" + "a = [[1, 0], [0, 1]]\n", + "b = [[4, 1], [2, 2]]\n", + "np.dot(a, b)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " 3)如果 `a` 或 `b` 是标量(维数为 0),那么其点积等价于乘,可以使用 `numpy.multiply(a,b)` 或 `a*b` 来表示;" ] }, { @@ -2283,7 +531,8 @@ { "data": { "text/plain": [ - "70" + "array([[16, 4],\n", + " [ 8, 8]])" ] }, "execution_count": 75, @@ -2292,115 +541,105 @@ } ], "source": [ - "1*5 + 2*6 + 3*7 + 4*8" - ] - }, - { - "attachments": { - "1707065960872.png": { - "image/png": "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" - } - }, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2.矩阵特征值\n", - "假设我们有一个 `n` 阶的矩阵 `A` 以及一个实数 `λ` ,使得我们可以找到一个非零向量 `x` ,满足:\n", - "\n", - "![1707065960872.png](attachment:1707065960872.png)\n", - "\n", - "如果能够找到的话,我们就称 `λ` 是矩阵 `A` 的特征值,非零向量 `x` 是矩阵 `A` 的特征向量。" + "a = 4\n", + "b = [[4,1],[2,2]]\n", + "np.dot(a,b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "我们可以使用 `linalg.eig(a)` 函数计算方阵的特征值(eigenvalues)和特征向量(eigenvectors)。" + " 4)如果`a` 是一维数组, `b` 是`N`维数组,那么点积是 `a` 与 `b` 的最后一个轴的积的和;" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, - "outputs": [], - "source": [ - "from numpy import linalg as LA" - ] - }, - { - "cell_type": "code", - "execution_count": 77, - "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "array([1., 2., 3.])" + "array([54, 66, 78])" ] }, - "execution_count": 77, + "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "eigenvalues, eigenvectors = LA.eig(np.diag((1, 2, 3)))\n", - "eigenvalues" + "a = [3,4,5]\n", + "b = [[1,2,3],[4,5,6],[7,8,9]]\n", + "np.dot(a,b)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " 5)如果`a` 是`N`维数组, `b` 是`M-d`维数组(M≥2),那么点积为 `a` 的最后一个轴与 `b` 的倒数第二条轴的乘机的和:\n", + " `dot(a,b)[i,j,k,m] = sum(a[i,j,:]*b[k,:,m])`" ] }, { "cell_type": "code", - "execution_count": 78, + "execution_count": 77, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "array([[1., 0., 0.],\n", - " [0., 1., 0.],\n", - " [0., 0., 1.]])" + "array([[ 70, 83, 96],\n", + " [ 60, 72, 84],\n", + " [ 90, 108, 126],\n", + " [106, 128, 150]])" ] }, - "execution_count": 78, + "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "eigenvectors" + "a = [[1,5,7],[2,4,6],[3,6,9],[4,8,10]]\n", + "b = [[1,2,3],[4,5,6],[7,8,9]]\n", + "np.dot(a,b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "我们还可以使用 `linalg.eigvals(a)` 函数计算一般矩阵的特征值。\n", - "与 `eig` 函数不同的是, `eigvals` 不返回特征向量。" + "### 矩阵特征值\n", + "\n", + "假设我们有一个 `n` 阶的矩阵 `A` 以及一个实数 `λ` ,使得我们可以找到一个非零向量 `x` ,满足:$Ax = \\lambda x$,如果能够找到的话,我们就称 `λ` 是矩阵 `A` 的特征值,非零向量 `x` 是矩阵 `A` 的特征向量。我们可以使用 `np.linalg.eig(a)` 函数计算方阵的特征值和特征向量。" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 83, "metadata": {}, + "outputs": [], "source": [ - "### 3.范数(norm)和秩(rank)\n", - "在线性代数中, 范数(norm)是一个表示“长度”概念的函数,为向量空间内的所有向量赋予非零的正长度或大小。" + "eigenvalues, eigenvectors = np.linalg.eig(np.diag((1, 2, 3)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "我们可以使用 `linalg.norm(x)` 函数计算矩阵或者向量的范数。" + "我们还可以使用 `np.linalg.eigvals(a)` 函数计算一般矩阵的特征值。\n", + "与 `np.linalg.eig()` 函数不同的是, `np.linalg.eigvals()` 不返回特征向量。" ] }, { - "cell_type": "code", - "execution_count": 79, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "from numpy import linalg as LA" + "### 范数(norm)和秩(rank)\n", + "在线性代数中, 范数(norm)是一个表示“长度”概念的函数,为向量空间内的所有向量赋予非零的正长度或大小。" ] }, { @@ -2412,7 +651,7 @@ }, { "cell_type": "code", - "execution_count": 80, + "execution_count": 84, "metadata": {}, "outputs": [ { @@ -2423,7 +662,7 @@ " [6, 7, 8]])" ] }, - "execution_count": 80, + "execution_count": 84, "metadata": {}, "output_type": "execute_result" } @@ -2436,7 +675,7 @@ }, { "cell_type": "code", - "execution_count": 81, + "execution_count": 85, "metadata": {}, "outputs": [ { @@ -2445,13 +684,13 @@ "14.2828568570857" ] }, - "execution_count": 81, + "execution_count": 85, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "LA.norm(a)" + "np.linalg.norm(a)" ] }, { @@ -2459,28 +698,12 @@ "metadata": {}, "source": [ "在线性代数中,一个矩阵 `A` 的列秩是 `A` 的线性独立的纵列的极大数,通常表示为 `r(A)` ,`rk(A)` 或 `rank A` 。\n", - "行秩是 `A` 的线性无关的横行的极大数目。即如果把矩阵看成一个个行向量或者列向量,秩就是这些行向量或者列向量的秩,也就是极大无关组中所含向量的个数。" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "我们可以使用 `linalg.matrix_rank(A)` 函数,使用 SVD 方法计算并返回数组的矩阵秩。" - ] - }, - { - "cell_type": "code", - "execution_count": 82, - "metadata": {}, - "outputs": [], - "source": [ - "from numpy.linalg import matrix_rank" + "行秩是 `A` 的线性无关的横行的极大数目。即如果把矩阵看成一个个行向量或者列向量,秩就是这些行向量或者列向量的秩,也就是极大无关组中所含向量的个数。我们可以使用 `np.linalg.matrix_rank(A)` 函数,使用 SVD 方法计算并返回数组的矩阵秩。" ] }, { "cell_type": "code", - "execution_count": 83, + "execution_count": 86, "metadata": {}, "outputs": [ { @@ -2489,13 +712,13 @@ "2" ] }, - "execution_count": 83, + "execution_count": 86, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "matrix_rank(a) " + "np.linalg.matrix_rank(a) " ] }, { @@ -2507,7 +730,7 @@ }, { "cell_type": "code", - "execution_count": 84, + "execution_count": 87, "metadata": {}, "outputs": [ { @@ -2519,7 +742,7 @@ " [0., 0., 0., 1.]])" ] }, - "execution_count": 84, + "execution_count": 87, "metadata": {}, "output_type": "execute_result" } @@ -2529,74 +752,23 @@ "b" ] }, - { - "cell_type": "code", - "execution_count": 85, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "4" - ] - }, - "execution_count": 85, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "matrix_rank(b) " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 4.解方程与逆" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### (1)方程求解" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "我们可以使用 `linalg.solve(a, b)` 函数求解线性矩阵方程或线性标量方程组。" + "### 解方程与逆" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "首先,我们生成矩阵 `a` 和 `b` 用于求解练习:" - ] - }, - { - "cell_type": "code", - "execution_count": 86, - "metadata": {}, - "outputs": [], - "source": [ - "a = np.array([[1, 2], [7, 9]])\n", - "b = np.array([1, 2])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "根据生成的矩阵中元素,我们可以列出所求解的方程组为 `x0+2*x1=1` 和 `7*x0+9*x1=2` 。" + "我们可以使用 `np.linalg.solve(a, b)` 函数求解线性矩阵方程或线性标量方程组。" ] }, { "cell_type": "code", - "execution_count": 87, + "execution_count": 88, "metadata": {}, "outputs": [ { @@ -2605,12 +777,14 @@ "array([-1., 1.])" ] }, - "execution_count": 87, + "execution_count": 88, "metadata": {}, "output_type": "execute_result" } ], "source": [ + "a = np.array([[1, 2], [7, 9]])\n", + "b = np.array([1, 2])\n", "x = np.linalg.solve(a, b)\n", "x" ] @@ -2619,26 +793,22 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### (2)矩阵求逆\n", - "设 `A` 是数域上的一个 `n` 阶方阵,若在相同数域上存在另一个 `n` 阶矩 `B` ,使得: `AB=BA=E` 。 \n", - "则我们称 `B` 是 `A` 的逆矩阵, `A` 则被称为可逆矩阵。\n", - "其中,`E` 为单位矩阵" + "根据生成的矩阵中元素,我们可以列出所求解的方程组为 `x0+2*x1=1` 和 `7*x0+9*x1=2` 。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "我们可以使用 `linalg.inv(a)` 函数对矩阵 `a` 求逆。" + "设 `A` 是数域上的一个 `n` 阶方阵,若在相同数域上存在另一个 `n` 阶矩 `B` ,使得: `AB=BA=E` 。则我们称 `B` 是 `A` 的逆矩阵, `A` 则被称为可逆矩阵。\n", + "其中,`E` 为单位矩阵" ] }, { - "cell_type": "code", - "execution_count": 88, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "from numpy.linalg import inv" + "我们可以使用 `np.linalg.inv(a)` 函数对矩阵 `a` 求逆。" ] }, { @@ -2649,8 +819,8 @@ { "data": { "text/plain": [ - "array([[1, 2],\n", - " [3, 4]])" + "array([[-2. , 1. ],\n", + " [ 1.5, -0.5]])" ] }, "execution_count": 89, @@ -2661,28 +831,7 @@ "source": [ "b = np.arange(4) +1\n", "a = b.reshape((2,2))\n", - "a" - ] - }, - { - "cell_type": "code", - "execution_count": 90, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[-2. , 1. ],\n", - " [ 1.5, -0.5]])" - ] - }, - "execution_count": 90, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "ainv = inv(a)\n", + "ainv = np.linalg.inv(a)\n", "ainv" ] } @@ -2703,7 +852,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.11" + "version": "3.11.7" } }, "nbformat": 4, diff --git a/ch-numpy/unary-ops.md b/ch-numpy/unary-ops.md deleted file mode 100644 index 39a4913..0000000 --- a/ch-numpy/unary-ops.md +++ /dev/null @@ -1 +0,0 @@ -# 一元函数 \ No newline at end of file diff --git a/conf.py b/conf.py index bbf9bed..8597296 100644 --- a/conf.py +++ b/conf.py @@ -40,7 +40,8 @@ "toc_title": "本节目录", } html_title = 'Python 数据科学实战' - +html_static_path = ["_static"] +html_css_files = ["custom.css"] html_js_files = [ "https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js", ] diff --git a/logo.png b/logo.png index 06d56f4..6d6e5ae 100644 Binary files a/logo.png and b/logo.png differ