Files
2024-09-25 18:29:02 +08:00

6006 lines
263 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",
"id": "cc79e031-c5ef-4dfc-8402-eacd0b7c6da3",
"metadata": {
"slideshow": {
"slide_type": "slide"
},
"tags": []
},
"source": [
"# 实验环境配置及基础编程训练\n",
"\n",
"## 目录\n",
"\n",
"- 实验配置补充说明\n",
"- Python 基础操作\n",
" - Numpy\n",
" - Matplotlib\n",
"- PyTorch 基础操作\n",
" - 基础数据操作\n",
"- 数据预处理\n",
"- 查阅文档\n",
"- 线性代数"
]
},
{
"cell_type": "markdown",
"id": "2a15f7b7-bed3-45af-bff6-96734985b337",
"metadata": {
"slideshow": {
"slide_type": "slide"
},
"tags": []
},
"source": [
"## 实验配置补充说明"
]
},
{
"cell_type": "markdown",
"id": "5a0c00c0-007d-4763-b902-c0d98a1b8cd2",
"metadata": {
"jp-MarkdownHeadingCollapsed": true,
"tags": []
},
"source": [
"### 命令行\n",
"\n",
"基础安装配置已在另一单独文档讲解,如果能正常运行到这里,说明实验环境已经基本配置成功了。\n",
"\n",
"即使之后的实验提示缺乏必要的软件包,也可以在 `JupyterLab` 集成的命令行终端中补充安装。\n",
"\n",
"> 注意:任何在 `JupyterLab` 集成的命令行终端中补充安装的软件包都会被安装到与启动 `JupyterLab` 相同的环境中。"
]
},
{
"cell_type": "markdown",
"id": "cb1d4d58-aa2a-4086-8517-5c72796debab",
"metadata": {},
"source": [
"具体操作步骤:\n",
"\n",
"1. `File -> New -> Terminal`;或 `File -> New Launcher`,然后选择 `Terminal`\n",
"2. 正常使用命令行工具更改运行环境"
]
},
{
"cell_type": "markdown",
"id": "2b26d1b4-cf1a-4940-8e31-7856fc959ae6",
"metadata": {
"slideshow": {
"slide_type": "subslide"
},
"tags": []
},
"source": [
"### 笔记中调用命令\n",
"\n",
"在Jupyter笔记本文件中也是可以直接调用终端命令的,例如查看当前环境的Python版本:"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "ea3122b2-935a-4814-a6f5-32724d90e05b",
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Python 3.8.16\n"
]
}
],
"source": [
"!python --version"
]
},
{
"cell_type": "markdown",
"id": "2f6f5920-aa1d-4c7d-8d88-2ea72e738cdf",
"metadata": {
"slideshow": {
"slide_type": "subslide"
},
"tags": []
},
"source": [
"### 调试器\n",
"\n",
"JupyterLab也集成了调试器:使用前需要先点击右上的`Enable Debugger`按钮。\n",
"\n",
"然后可以正常使用设置断点、单步执行、查看变量等操作。"
]
},
{
"cell_type": "markdown",
"id": "c596f9c2-1cbf-443d-ba3d-8062e30ba7b0",
"metadata": {
"jp-MarkdownHeadingCollapsed": true,
"slideshow": {
"slide_type": "slide"
},
"tags": []
},
"source": [
"## Python 基础操作"
]
},
{
"cell_type": "markdown",
"id": "536bf0be-5558-4704-83f3-29810c4d5b33",
"metadata": {
"jp-MarkdownHeadingCollapsed": true,
"tags": []
},
"source": [
"Python本身是一种强大的通用编程语言,但在一些流行的库(`numpy`、`scipy`、`matplotlib`)的帮助下,它成为一种更加强大的科学计算环境。\n",
"\n",
"我们希望你们中的许多人对`Python`和`numpy`有一些经验;对于其余的人,本节将作为`Python`编程语言和`Python`在科学计算中的应用的快速入门课程。"
]
},
{
"cell_type": "markdown",
"id": "09ed020e-157c-46ba-a3ba-23a46cb1c6e4",
"metadata": {},
"source": [
"Python是一种高级的、动态类型的多范式编程语言。人们常说Python代码几乎就是伪代码,因为它允许你用很少的几行代码来表达非常强大的思想,同时又非常可读。"
]
},
{
"cell_type": "markdown",
"id": "454e6f4f-d5d2-464d-bd35-0b21f8fd0b82",
"metadata": {
"id": "NwS_hu4xL9eo",
"slideshow": {
"slide_type": "slide"
},
"tags": []
},
"source": [
"### 基础数据类型"
]
},
{
"cell_type": "markdown",
"id": "62880ea3-9a6a-4274-b944-ca76d6d922de",
"metadata": {
"id": "DL5sMSZ9L9eq"
},
"source": [
"#### 数值型\n",
"\n",
"整数和浮点数的工作方式与其他语言几乎一样。"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "92debbb1-0b9b-447d-b31e-adeba820bc73",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "KheDr_zDL9es",
"outputId": "1db9f4d3-2e0d-4008-f78a-161ed52c4359",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3 <class 'int'>\n"
]
}
],
"source": [
"x = 3\n",
"print(x, type(x))"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "d5ccd284-e91b-4bd9-9dde-640ca8b69791",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 86
},
"id": "sk_8DFcuL9ey",
"outputId": "dd60a271-3457-465d-e16a-41acf12a56ab",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"4\n",
"2\n",
"6\n",
"9\n"
]
}
],
"source": [
"print(x + 1) # Addition\n",
"print(x - 1) # Subtraction\n",
"print(x * 2) # Multiplication\n",
"print(x ** 2) # Exponentiation"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "144bc983-be47-4e00-b0fc-1f5e511be462",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "U4Jl8K0tL9e4",
"outputId": "07e3db14-3781-42b7-8ba6-042b3f9f72ba",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"4\n",
"8\n"
]
}
],
"source": [
"x += 1\n",
"print(x)\n",
"x *= 2\n",
"print(x)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "ce0b350d-6308-4418-b450-6a480e5d38fb",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "w-nZ0Sg_L9e9",
"outputId": "3aa579f8-9540-46ef-935e-be887781ecb4",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<class 'float'>\n",
"2.5 3.5 5.0 6.25\n"
]
}
],
"source": [
"y = 2.5\n",
"print(type(y))\n",
"print(y, y + 1, y * 2, y ** 2)"
]
},
{
"cell_type": "markdown",
"id": "0b7beebc-96b7-4b62-86e2-6d946329643d",
"metadata": {
"id": "r2A9ApyaL9fB"
},
"source": [
"注意,与许多语言不同,Python 没有单数增量 (`x++`) 或减量 (`x--`) 操作符。\n",
"\n",
"Python 也有长整数和复数的内置类型;如有疑问,可查看[文档细节](https://docs.python.org/zh-cn/3.11/library/stdtypes.html#numeric-types-int-float-long-complex)。\n"
]
},
{
"cell_type": "markdown",
"id": "322ab33a-c59e-40a3-976e-322d162d8cdd",
"metadata": {
"id": "EqRS7qhBL9fC"
},
"source": [
"#### 布尔型\n",
"\n",
"Python 实现了布尔逻辑的所有常用运算符,但使用英文单词而不是符号 (`&&`, `||`, 等等)。"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "63e4ccf6-d7ce-4f3b-bb01-e945b9418ef6",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"id": "RvoImwgGL9fE",
"outputId": "1517077b-edca-463f-857b-6a8c386cd387",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<class 'bool'>\n"
]
}
],
"source": [
"t, f = True, False\n",
"print(type(t))"
]
},
{
"cell_type": "markdown",
"id": "9616f32f-2069-4dc3-85ee-761351f1a233",
"metadata": {
"id": "YQgmQfOgL9fI"
},
"source": [
"现在我们来看看这些操作:"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "196b2bd3-d3a4-4328-8245-4b337f6002d8",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 86
},
"id": "6zYm7WzCL9fK",
"outputId": "f3cebe76-5af4-473a-8127-88a1fd60560f",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"False\n",
"True\n",
"False\n",
"True\n"
]
}
],
"source": [
"print(t and f) # Logical AND;\n",
"print(t or f) # Logical OR;\n",
"print(not t) # Logical NOT;\n",
"print(t != f) # Logical XOR;"
]
},
{
"cell_type": "markdown",
"id": "97598521-e74e-47e3-a4dd-b6ae18a35063",
"metadata": {
"id": "UQnQWFEyL9fP"
},
"source": [
"#### 字符串\n",
"\n",
"字符串不区分单引号或双引号:"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "f5ea11d3-5c0a-4218-b0a2-9323e16712de",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"id": "AijEDtPFL9fP",
"outputId": "2a6b0cd7-58f1-43cf-e6b7-bf940d532549",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"hello 5\n"
]
}
],
"source": [
"hello = 'hello' # String literals can use single quotes\n",
"world = \"world\" # or double quotes; it does not matter\n",
"print(hello, len(hello))"
]
},
{
"cell_type": "markdown",
"id": "0a58a167-5f3f-4d57-8aac-d2b27a756094",
"metadata": {
"tags": []
},
"source": [
"字符串拼接:"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "edbe74f8-8d03-491d-a34f-b19537328dd7",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"id": "saDeaA7hL9fT",
"outputId": "2837d0ab-9ae5-4053-d087-bfa0af81c344",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"hello world\n"
]
}
],
"source": [
"hw = hello + ' ' + world # String concatenation\n",
"print(hw)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "651bbbd3-90e6-4dd2-9b87-178ea11db68e",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"id": "Nji1_UjYL9fY",
"outputId": "0149b0ca-425a-4a34-8e24-8dff7080922e",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"hello world 12\n"
]
}
],
"source": [
"hw12 = '{} {} {}'.format(hello, world, 12) # string formatting\n",
"print(hw12)"
]
},
{
"cell_type": "markdown",
"id": "3a258cf4-aac1-4ccc-b3f5-3889c4180987",
"metadata": {},
"source": [
"最新版Python里(3.7以上)推荐使用“f-string”格式化字符串:"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "a76bcee8-fecd-4247-997c-8c23b19f7d4e",
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"hello, world 12\n"
]
}
],
"source": [
"print(f'{hello}, {world} {12}')"
]
},
{
"cell_type": "markdown",
"id": "517f3f58-3252-4808-bc12-c2023540667d",
"metadata": {
"id": "bUpl35bIL9fc"
},
"source": [
"字符串对象有很多有用的方法;例如:"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "0d0dcfa1-36b5-48c1-99d9-3406c6f8f81e",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 121
},
"id": "VOxGatlsL9fd",
"outputId": "ab009df3-8643-4d3e-f85f-a813b70db9cb",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Hello\n",
"HELLO\n",
" hello\n",
" hello \n",
"he(ell)(ell)o\n",
"world\n"
]
}
],
"source": [
"s = \"hello\"\n",
"print(s.capitalize()) # Capitalize a string\n",
"print(s.upper()) # Convert a string to uppercase; prints \"HELLO\"\n",
"print(s.rjust(7)) # Right-justify a string, padding with spaces\n",
"print(s.center(7)) # Center a string, padding with spaces\n",
"print(s.replace('l', '(ell)')) # Replace all instances of one substring with another\n",
"print(' world '.strip()) # Strip leading and trailing whitespace"
]
},
{
"cell_type": "markdown",
"id": "aae8a237-8bde-4b8a-bcb0-45e9234fd8b2",
"metadata": {
"id": "06cayXLtL9fi"
},
"source": [
"你可以在[文档](https://docs.python.org/zh-cn/3.11/library/stdtypes.html#string-methods)中找到所有字符串方法的列表。"
]
},
{
"cell_type": "markdown",
"id": "8ce225b4-1283-42f1-a5da-0c07333bc94e",
"metadata": {
"id": "p-6hClFjL9fk",
"tags": []
},
"source": [
"### 容器\n",
"\n",
"Python 包括几种内置的容器类型:列表、字典、集合和图元。"
]
},
{
"cell_type": "markdown",
"id": "3c63d495-90bb-4eae-af27-0a39dcdf31d8",
"metadata": {
"id": "UsIWOe0LL9fn"
},
"source": [
"#### 列表\n",
"\n",
"列表相当于数组,但是可以调整大小,并且可以包含不同类型的元素。"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "3fb8f690-2e82-4823-8e92-68171a82d44c",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "hk3A8pPcL9fp",
"outputId": "b545939a-580c-4356-db95-7ad3670b46e4",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[3, 1, 2] 2\n",
"2\n"
]
}
],
"source": [
"xs = [3, 1, 2] # Create a list\n",
"print(xs, xs[2])\n",
"print(xs[-1]) # Negative indices count from the end of the list; prints \"2\""
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "97736c21-b355-431c-a9b4-005d9e46e3e2",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"id": "YCjCy_0_L9ft",
"outputId": "417c54ff-170b-4372-9099-0f756f8e48af",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[3, 1, 'foo']\n"
]
}
],
"source": [
"xs[2] = 'foo' # Lists can contain elements of different types\n",
"print(xs)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "ba24ceaf-92b3-4777-b162-6b56b36e8235",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"id": "vJ0x5cF-L9fx",
"outputId": "a97731a3-70e1-4553-d9e0-2aea227cac80",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[3, 1, 'foo', 'bar']\n"
]
}
],
"source": [
"xs.append('bar') # Add a new element to the end of the list\n",
"print(xs) "
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "22a59aee-504c-47be-838c-92514fa79abc",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"id": "cxVCNRTNL9f1",
"outputId": "508fbe59-20aa-48b5-a1b2-f90363e7a104",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"bar [3, 1, 'foo']\n"
]
}
],
"source": [
"x = xs.pop() # Remove and return the last element of the list\n",
"print(x, xs)"
]
},
{
"cell_type": "markdown",
"id": "2a8d5172-0e96-4b56-8dbd-0a3b99a2f386",
"metadata": {},
"source": [
"像往常一样,你可以在[文档](https://docs.python.org/zh-cn/3.11/tutorial/datastructures.html#more-on-lists)中找到关于列表的所有细节。"
]
},
{
"cell_type": "markdown",
"id": "3336e208-433f-42d0-9138-0263175c8b52",
"metadata": {
"id": "ovahhxd_L9f5"
},
"source": [
"#### 数据切片\n",
"\n",
"除了每次访问列表元素之外,Python 还提供了简洁的语法来访问子列表;这被称为切片。"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "23f6cd10-738b-441e-b8a4-1b365e21e0c9",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 139
},
"id": "ninq666bL9f6",
"outputId": "c3c2ed92-7358-4fdb-bbc0-e90f82e7e941",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[0, 1, 2, 3, 4]\n",
"[2, 3]\n",
"[2, 3, 4]\n",
"[0, 1]\n",
"[0, 1, 2, 3, 4]\n",
"[0, 1, 2, 3]\n",
"[0, 1, 8, 9, 4]\n"
]
}
],
"source": [
"nums = list(range(5)) # range is a built-in function that creates a list of integers\n",
"print(nums) # Prints \"[0, 1, 2, 3, 4]\"\n",
"print(nums[2:4]) # Get a slice from index 2 to 4 (exclusive); prints \"[2, 3]\"\n",
"print(nums[2:]) # Get a slice from index 2 to the end; prints \"[2, 3, 4]\"\n",
"print(nums[:2]) # Get a slice from the start to index 2 (exclusive); prints \"[0, 1]\"\n",
"print(nums[:]) # Get a slice of the whole list; prints [\"0, 1, 2, 3, 4]\"\n",
"print(nums[:-1]) # Slice indices can be negative; prints [\"0, 1, 2, 3]\"\n",
"nums[2:4] = [8, 9] # Assign a new sublist to a slice\n",
"print(nums) # Prints \"[0, 1, 8, 9, 4]\""
]
},
{
"cell_type": "markdown",
"id": "e31c6e89-fd6e-4a4c-95d3-49a92e773d6d",
"metadata": {
"id": "UONpMhF4L9f_"
},
"source": [
"#### 遍历\n",
"\n",
"遍历列表元素在Python中也非常简洁:"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "2aa575f8-3016-453a-86aa-faf3b691f572",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 69
},
"id": "4cCOysfWL9gA",
"outputId": "560e46c7-279c-409a-838c-64bea8d321c4",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"cat\n",
"dog\n",
"monkey\n"
]
}
],
"source": [
"animals = ['cat', 'dog', 'monkey']\n",
"for animal in animals:\n",
" print(animal)"
]
},
{
"cell_type": "markdown",
"id": "07ea5b44-6e3b-4662-b015-d4aae4c497a4",
"metadata": {},
"source": [
"如果你想访问一个循环体内每个元素的索引,请使用内置的`enumerate`函数。"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "ea3e8838-3dc8-4636-bf9c-ca5ee3445ae8",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 69
},
"id": "JjGnDluWL9gF",
"outputId": "81421905-17ea-4c5a-bcc0-176de19fd9bd",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"#1: cat\n",
"#2: dog\n",
"#3: monkey\n"
]
}
],
"source": [
"animals = ['cat', 'dog', 'monkey']\n",
"for idx, animal in enumerate(animals):\n",
" print('#{}: {}'.format(idx + 1, animal))"
]
},
{
"cell_type": "markdown",
"id": "ce76067a-6cb3-4742-892a-51094b1357f2",
"metadata": {
"id": "arrLCcMyL9gK"
},
"source": [
"#### 列表理解\n",
"\n",
"在编程时,我们经常想把一种类型的数据转换成另一种类型的数据。作为一个简单的例子,考虑以下计算平方数的代码。"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "5587ed10-64d0-49d2-b299-afbb34b4cab6",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"id": "IVNEwoMXL9gL",
"outputId": "d571445b-055d-45f0-f800-24fd76ceec5a",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[0, 1, 4, 9, 16]\n"
]
}
],
"source": [
"nums = [0, 1, 2, 3, 4]\n",
"squares = []\n",
"for x in nums:\n",
" squares.append(x ** 2)\n",
"print(squares)"
]
},
{
"cell_type": "markdown",
"id": "2755e0f7-430f-4f5b-9f77-601ff6573027",
"metadata": {
"id": "7DmKVUFaL9gQ"
},
"source": [
"你可以用列表理解法使这段代码更简单。"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "a9d47d92-4383-41bb-be05-4c9d9af25362",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"id": "kZxsUfV6L9gR",
"outputId": "4254a7d4-58ba-4f70-a963-20c46b485b72",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[0, 1, 4, 9, 16]\n"
]
}
],
"source": [
"nums = [0, 1, 2, 3, 4]\n",
"squares = [x ** 2 for x in nums]\n",
"print(squares)"
]
},
{
"cell_type": "markdown",
"id": "25f6e74b-15f4-4360-8f77-c9b5d48bc8d0",
"metadata": {
"id": "-D8ARK7tL9gV"
},
"source": [
"列表理解也可以包含条件:"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "c0e48840-6751-47ed-b1b1-3f26ba8d155a",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"id": "yUtgOyyYL9gV",
"outputId": "1ae7ab58-8119-44dc-8e57-fda09197d026",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[0, 4, 16]\n"
]
}
],
"source": [
"nums = [0, 1, 2, 3, 4]\n",
"even_squares = [x ** 2 for x in nums if x % 2 == 0]\n",
"print(even_squares)"
]
},
{
"cell_type": "markdown",
"id": "7db9e9a4-6638-4d19-82f6-7f6c599e82d7",
"metadata": {
"id": "H8xsUEFpL9gZ",
"tags": []
},
"source": [
"### 字典\n",
"\n",
"`dictionary` 存储对 `(key, value)`,类似于 Java 中的 `Map` 或 Javascript 中的对象。"
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "550e661f-e598-4ec8-b6d0-d99bb81e6f53",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "XBYI1MrYL9gb",
"outputId": "8e24c1da-0fc0-4b4c-a3e6-6f758a53b7da",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"cute\n",
"True\n"
]
}
],
"source": [
"d = {'cat': 'cute', 'dog': 'furry'} # Create a new dictionary with some data\n",
"print(d['cat']) # Get an entry from a dictionary; prints \"cute\"\n",
"print('cat' in d) # Check if a dictionary has a given key; prints \"True\""
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "089c01a4-49d7-46a0-9fbc-2b54d9e7a051",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"id": "pS7e-G-HL9gf",
"outputId": "feb4bf18-c0a3-42a2-eaf5-3fc390f36dcf",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"wet\n"
]
}
],
"source": [
"d['fish'] = 'wet' # Set an entry in a dictionary\n",
"print(d['fish']) # Prints \"wet\""
]
},
{
"cell_type": "code",
"execution_count": 31,
"id": "8bd7abd2-3817-4210-b131-cbe653fe00ab",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 165
},
"id": "tFY065ItL9gi",
"outputId": "7e42a5f0-1856-4608-a927-0930ab37a66c",
"tags": []
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Traceback (most recent call last):\n",
" File \"/var/folders/zv/bzxgq5_j5f9gkpm84rg80kph0000gn/T/ipykernel_31837/1743455973.py\", line 3, in <module>\n",
" print(d['monkey']) # KeyError: 'monkey' not a key of d\n",
"KeyError: 'monkey'\n"
]
}
],
"source": [
"import traceback\n",
"try:\n",
" print(d['monkey']) # KeyError: 'monkey' not a key of d\n",
"except Exception as e:\n",
" traceback.print_exc()"
]
},
{
"cell_type": "code",
"execution_count": 32,
"id": "1097ca3d-f41d-484a-9aac-a3836df4e211",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "8TjbEWqML9gl",
"outputId": "ef14d05e-401d-4d23-ed1a-0fe6b4c77d6f",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"N/A\n",
"wet\n"
]
}
],
"source": [
"print(d.get('monkey', 'N/A')) # Get an element with a default; prints \"N/A\"\n",
"print(d.get('fish', 'N/A')) # Get an element with a default; prints \"wet\""
]
},
{
"cell_type": "code",
"execution_count": 33,
"id": "6405b789-d95d-4e88-a5de-cf9416b36d3c",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"id": "0EItdNBJL9go",
"outputId": "652a950f-b0c2-4623-98bd-0191b300cd57",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"N/A\n"
]
}
],
"source": [
"del d['fish'] # Remove an element from a dictionary\n",
"print(d.get('fish', 'N/A')) # \"fish\" is no longer a key; prints \"N/A\""
]
},
{
"cell_type": "markdown",
"id": "cbe19427-0004-4670-86af-ce7358f14689",
"metadata": {
"id": "IxwEqHlGL9gr"
},
"source": [
"遍历字典中的关键字:"
]
},
{
"cell_type": "code",
"execution_count": 34,
"id": "4063d23c-ee46-4d50-8e89-d355d39d1d8c",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 69
},
"id": "rYfz7ZKNL9gs",
"outputId": "155bdb17-3179-4292-c832-8166e955e942",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"A person has 2 legs\n",
"A cat has 4 legs\n",
"A spider has 8 legs\n"
]
}
],
"source": [
"d = {'person': 2, 'cat': 4, 'spider': 8}\n",
"for animal, legs in d.items():\n",
" print('A {} has {} legs'.format(animal, legs))"
]
},
{
"cell_type": "markdown",
"id": "f6cfaebb-9616-4051-a29f-819f80b19ccd",
"metadata": {
"id": "17sxiOpzL9gz"
},
"source": [
"字典理解与列表理解类似,但允许你轻松构建字典:"
]
},
{
"cell_type": "code",
"execution_count": 35,
"id": "5e892ea9-2373-46e7-b3b3-b090d58f6ec7",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"id": "8PB07imLL9gz",
"outputId": "e9ddf886-39ed-4f35-dd80-64a19d2eec9b",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{0: 0, 2: 4, 4: 16}\n"
]
}
],
"source": [
"nums = [0, 1, 2, 3, 4]\n",
"even_num_to_square = {x: x ** 2 for x in nums if x % 2 == 0}\n",
"print(even_num_to_square)"
]
},
{
"cell_type": "markdown",
"id": "bc64fa19-0405-47aa-aa0f-bf78e543115b",
"metadata": {},
"source": [
"你可以在[文档](https://docs.python.org/3/tutorial/datastructures.html#dictionaries)中找到所有你需要知道的关于字典的信息。"
]
},
{
"cell_type": "markdown",
"id": "ac1224a2-0c3d-4f9c-adcc-5c5c3883cc84",
"metadata": {
"id": "V9MHfUdvL9g2"
},
"source": [
"#### 集合\n",
"\n",
"集合是一个由不同元素组成的无序集合。"
]
},
{
"cell_type": "code",
"execution_count": 36,
"id": "587cd6cc-03bf-49cc-875b-4bca003add02",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "MmyaniLsL9g2",
"outputId": "8f152d48-0a07-432a-cf98-8de4fd57ddbb",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n",
"False\n"
]
}
],
"source": [
"animals = {'cat', 'dog'}\n",
"print('cat' in animals) # Check if an element is in a set; prints \"True\"\n",
"print('fish' in animals) # prints \"False\"\n"
]
},
{
"cell_type": "code",
"execution_count": 37,
"id": "646a17ac-74b7-4f25-b152-8642ede7088b",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "ElJEyK86L9g6",
"outputId": "b9d7dab9-5a98-41cd-efbc-786d0c4377f7",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n",
"3\n"
]
}
],
"source": [
"animals.add('fish') # Add an element to a set\n",
"print('fish' in animals)\n",
"print(len(animals)) # Number of elements in a set;"
]
},
{
"cell_type": "code",
"execution_count": 38,
"id": "981d0004-8861-44da-9347-b0cd06908485",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "5uGmrxdPL9g9",
"outputId": "e644d24c-26c6-4b43-ab15-8aa81fe884d4",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3\n",
"2\n"
]
}
],
"source": [
"animals.add('cat') # Adding an element that is already in the set does nothing\n",
"print(len(animals)) \n",
"animals.remove('cat') # Remove an element from a set\n",
"print(len(animals)) "
]
},
{
"cell_type": "markdown",
"id": "3830fb70-27dc-404e-9c49-a90e586f9008",
"metadata": {
"tags": []
},
"source": [
"循环:对集合进行迭代的语法与对列表进行迭代的语法相同;但是由于集合是无序的,你不能对访问集合中的元素的顺序做出假设。"
]
},
{
"cell_type": "code",
"execution_count": 39,
"id": "da338585-7f7e-4d94-a9a6-628133b50f94",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 69
},
"id": "K47KYNGyL9hA",
"outputId": "4477f897-4355-4816-b39b-b93ffbac4bf0",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"#1: fish\n",
"#2: dog\n",
"#3: cat\n"
]
}
],
"source": [
"animals = {'cat', 'dog', 'fish'}\n",
"for idx, animal in enumerate(animals):\n",
" print('#{}: {}'.format(idx + 1, animal))"
]
},
{
"cell_type": "markdown",
"id": "7a06bf28-d149-4b45-9df0-34da529fd78c",
"metadata": {
"id": "puq4S8buL9hC"
},
"source": [
"集合理解:像列表和字典一样,我们可以用集合理解法轻松地构建集合。"
]
},
{
"cell_type": "code",
"execution_count": 40,
"id": "fea46a27-7797-46a3-b3b5-473f801481fc",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"id": "iw7k90k3L9hC",
"outputId": "72d6b824-6d31-47b2-f929-4cf434590ee5",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{0, 1, 2, 3, 4, 5}\n"
]
}
],
"source": [
"from math import sqrt\n",
"print({int(sqrt(x)) for x in range(30)})"
]
},
{
"cell_type": "markdown",
"id": "da599c6a-e1f7-46cd-8202-246ae074cd96",
"metadata": {
"id": "qPsHSKB1L9hF"
},
"source": [
"#### 元组\n",
"\n",
"元组是一个(不可变的)有序的数值列表。元组在许多方面与列表相似;最重要的区别之一是,元组可以作为字典的键和集合的元素,而列表则不能。"
]
},
{
"cell_type": "code",
"execution_count": 41,
"id": "d7d2eccc-5f3f-4995-b685-398b60a7c027",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 69
},
"id": "9wHUyTKxL9hH",
"outputId": "cdc5f620-04fe-4b0b-df7a-55b061d23d88",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<class 'tuple'>\n",
"5\n",
"1\n"
]
}
],
"source": [
"d = {(x, x + 1): x for x in range(10)} # Create a dictionary with tuple keys\n",
"t = (5, 6) # Create a tuple\n",
"print(type(t))\n",
"print(d[t]) \n",
"print(d[(1, 2)])"
]
},
{
"cell_type": "code",
"execution_count": 43,
"id": "4637f799-d63d-4c44-ad59-be6317a23dca",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 165
},
"id": "HoO8zYKzL9hJ",
"outputId": "28862bfc-0298-40d7-f8c4-168e109d2d93",
"tags": []
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Traceback (most recent call last):\n",
" File \"/var/folders/zv/bzxgq5_j5f9gkpm84rg80kph0000gn/T/ipykernel_31837/743935956.py\", line 3, in <module>\n",
" t[0] = 1 # TypeError: 'tuple' object does not support item assignment\n",
"TypeError: 'tuple' object does not support item assignment\n"
]
}
],
"source": [
"import traceback\n",
"try:\n",
" t[0] = 1 # TypeError: 'tuple' object does not support item assignment\n",
"except Exception as e:\n",
" traceback.print_exc()"
]
},
{
"cell_type": "markdown",
"id": "58fd22de-586a-4214-a608-c915964b01af",
"metadata": {
"id": "AXA4jrEOL9hM",
"jp-MarkdownHeadingCollapsed": true,
"tags": []
},
"source": [
"### 函数\n",
"\n",
"Python 函数是用 `def` 关键字定义的。"
]
},
{
"cell_type": "code",
"execution_count": 44,
"id": "d1ff2700-4910-49d3-ae32-51ebd6fb83ba",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 69
},
"id": "kiMDUr58L9hN",
"outputId": "9f53bf9a-7b2a-4c51-9def-398e4677cd6c",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"negative\n",
"zero\n",
"positive\n"
]
}
],
"source": [
"def sign(x):\n",
" if x > 0:\n",
" return 'positive'\n",
" elif x < 0:\n",
" return 'negative'\n",
" else:\n",
" return 'zero'\n",
"\n",
"for x in [-1, 0, 1]:\n",
" print(sign(x))"
]
},
{
"cell_type": "markdown",
"id": "bfcc59de-5a62-4a95-a75f-4bd161238a91",
"metadata": {},
"source": [
"我们可以像这样定义函数来接受可选的关键字参数。"
]
},
{
"cell_type": "code",
"execution_count": 45,
"id": "06d000b0-59bb-4a69-adaa-c93159f6661f",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "PfsZ3DazL9hR",
"outputId": "6e6af832-67d8-4d8c-949b-335927684ae3",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Hello, Bob!\n",
"HELLO, FRED\n"
]
}
],
"source": [
"def hello(name, loud=False):\n",
" if loud:\n",
" print('HELLO, {}'.format(name.upper()))\n",
" else:\n",
" print('Hello, {}!'.format(name))\n",
"\n",
"hello('Bob')\n",
"hello('Fred', loud=True)"
]
},
{
"cell_type": "markdown",
"id": "b87320a3-5ca9-4c64-be86-1b026bf6b125",
"metadata": {
"id": "ObA9PRtQL9hT",
"jp-MarkdownHeadingCollapsed": true,
"tags": []
},
"source": [
"### 类\n",
"\n",
"在Python中定义类的语法与其他面向对象语言类似。"
]
},
{
"cell_type": "code",
"execution_count": 46,
"id": "60d14004-4a28-46d9-8861-f2236fa0c452",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "RWdbaGigL9hU",
"outputId": "4f6615c5-75a7-4ce4-8ea1-1e7f5e4e9fc3",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Hello, Fred!\n",
"HELLO, FRED\n"
]
}
],
"source": [
"class Greeter:\n",
"\n",
" # Constructor\n",
" def __init__(self, name):\n",
" self.name = name # Create an instance variable\n",
"\n",
" # Instance method\n",
" def greet(self, loud=False):\n",
" if loud:\n",
" print('HELLO, {}'.format(self.name.upper()))\n",
" else:\n",
" print('Hello, {}!'.format(self.name))\n",
"\n",
"g = Greeter('Fred') # Construct an instance of the Greeter class\n",
"g.greet() # Call an instance method; prints \"Hello, Fred\"\n",
"g.greet(loud=True) # Call an instance method; prints \"HELLO, FRED!\""
]
},
{
"cell_type": "markdown",
"id": "d52b89c1-b890-409f-80e5-3e321679d5e0",
"metadata": {
"id": "3cfrOV4dL9hW",
"jp-MarkdownHeadingCollapsed": true,
"tags": []
},
"source": [
"## Numpy"
]
},
{
"cell_type": "markdown",
"id": "9821dc0b-b68c-4309-958f-46abdae7f2a3",
"metadata": {
"id": "3cfrOV4dL9hW",
"jp-MarkdownHeadingCollapsed": true,
"tags": []
},
"source": [
"Numpy是Python中科学计算的核心库。它提供了一个高性能的多维数组对象,以及处理这些数组的工具。\n",
"\n",
"要使用Numpy,我们首先需要导入`numpy`包。"
]
},
{
"cell_type": "code",
"execution_count": 47,
"id": "545df4bf-976e-42f8-be87-2b225846ca48",
"metadata": {
"id": "58QdX8BLL9hZ",
"tags": []
},
"outputs": [],
"source": [
"import numpy as np"
]
},
{
"cell_type": "markdown",
"id": "83fec0fa-5c2d-4490-b045-5570471a986f",
"metadata": {
"id": "DDx6v1EdL9hb",
"tags": []
},
"source": [
"### 数组\n",
"\n",
"numpy数组是一个由数值组成的网格,所有的数值都是相同的类型,并由一个非负整数的元组来索引。维数的数量是数组的等级;数组的形状是一个整数的元组,给出数组在每个维度上的大小。"
]
},
{
"cell_type": "markdown",
"id": "0bd6e576-1a11-432c-9b12-fee1a96bc1d4",
"metadata": {},
"source": [
"我们可以从嵌套的Python列表中初始化numpy数组,并使用方括号访问元素。"
]
},
{
"cell_type": "code",
"execution_count": 48,
"id": "6af27792-1ec3-48c6-a50e-2222092a30d0",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "-l3JrGxCL9hc",
"outputId": "8d9dad18-c734-4a8a-ca8c-44060a40fb79",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<class 'numpy.ndarray'> (3,) 1 2 3\n",
"[5 2 3]\n"
]
}
],
"source": [
"a = np.array([1, 2, 3]) # Create a rank 1 array\n",
"print(type(a), a.shape, a[0], a[1], a[2])\n",
"a[0] = 5 # Change an element of the array\n",
"print(a) "
]
},
{
"cell_type": "code",
"execution_count": 49,
"id": "f559d4a6-3589-4e81-8855-7b59f62a0873",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "ma6mk-kdL9hh",
"outputId": "0b54ff2f-e7f1-4b30-c653-9bf81cb8fbb0",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[1 2 3]\n",
" [4 5 6]]\n"
]
}
],
"source": [
"b = np.array([[1,2,3],[4,5,6]]) # Create a rank 2 array\n",
"print(b)"
]
},
{
"cell_type": "code",
"execution_count": 50,
"id": "aae07be5-11b2-4d38-9b9b-cde518cb7bfa",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "ymfSHAwtL9hj",
"outputId": "5bd292d8-c751-43b9-d480-f357dde52342",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(2, 3)\n",
"1 2 4\n"
]
}
],
"source": [
"print(b.shape)\n",
"print(b[0, 0], b[0, 1], b[1, 0])"
]
},
{
"cell_type": "markdown",
"id": "686760a7-1358-4e70-9f87-d55c16f479b0",
"metadata": {},
"source": [
"Numpy还提供了许多创建数组的函数。"
]
},
{
"cell_type": "code",
"execution_count": 51,
"id": "56264728-2c1d-4280-9fc4-2643a9ca0a40",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "mVTN_EBqL9hn",
"outputId": "d267c65f-ba90-4043-cedb-f468ab1bcc5d",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[0. 0.]\n",
" [0. 0.]]\n"
]
}
],
"source": [
"a = np.zeros((2,2)) # Create an array of all zeros\n",
"print(a)"
]
},
{
"cell_type": "code",
"execution_count": 52,
"id": "131e2011-a8f8-4082-b234-e132284b2a81",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"id": "skiKlNmlL9h5",
"outputId": "7d1ec1b5-a1fe-4f44-cbe3-cdeacad425f1",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[1. 1.]]\n"
]
}
],
"source": [
"b = np.ones((1,2)) # Create an array of all ones\n",
"print(b)"
]
},
{
"cell_type": "code",
"execution_count": 53,
"id": "cfd9b07e-e046-4e93-91c3-b185b24304af",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "HtFsr03bL9h7",
"outputId": "2688b157-2fad-4fc6-f20b-8633207f0326",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[7 7]\n",
" [7 7]]\n"
]
}
],
"source": [
"c = np.full((2,2), 7) # Create a constant array\n",
"print(c)"
]
},
{
"cell_type": "code",
"execution_count": 54,
"id": "03a22b15-abd7-434d-b10f-a5407eba4f1e",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "-QcALHvkL9h9",
"outputId": "5035d6fe-cb7e-4222-c972-55fe23c9d4c0",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[1. 0.]\n",
" [0. 1.]]\n"
]
}
],
"source": [
"d = np.eye(2) # Create a 2x2 identity matrix\n",
"print(d)"
]
},
{
"cell_type": "code",
"execution_count": 55,
"id": "5657a511-97df-4277-b8f5-4e547002387e",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "RCpaYg9qL9iA",
"outputId": "25f0b387-39cf-42f3-8701-de860cc75e2e",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[0.00480263 0.8985954 ]\n",
" [0.19113444 0.57867786]]\n"
]
}
],
"source": [
"e = np.random.random((2,2)) # Create an array filled with random values\n",
"print(e)"
]
},
{
"cell_type": "markdown",
"id": "428e2575-e475-4a49-99d9-6da69e0c72af",
"metadata": {
"id": "jI5qcSDfL9iC",
"jp-MarkdownHeadingCollapsed": true,
"tags": []
},
"source": [
"### 数组索引\n",
"\n",
"切片:与Python列表类似,numpy数组可以被切片。由于数组可能是多维的,你必须为数组的每个维度指定一个分片。"
]
},
{
"cell_type": "code",
"execution_count": 56,
"id": "c5d07ae7-a2e9-468f-a4e9-e529addcedde",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "wLWA0udwL9iD",
"outputId": "99f08618-c513-4982-8982-b146fc72dab3",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[2 3]\n",
" [6 7]]\n"
]
}
],
"source": [
"import numpy as np\n",
"\n",
"# Create the following rank 2 array with shape (3, 4)\n",
"# [[ 1 2 3 4]\n",
"# [ 5 6 7 8]\n",
"# [ 9 10 11 12]]\n",
"a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])\n",
"\n",
"# Use slicing to pull out the subarray consisting of the first 2 rows\n",
"# and columns 1 and 2; b is the following array of shape (2, 2):\n",
"# [[2 3]\n",
"# [6 7]]\n",
"b = a[:2, 1:3]\n",
"print(b)"
]
},
{
"cell_type": "markdown",
"id": "76bb97fc-6a08-4803-8c03-183483453aa5",
"metadata": {},
"source": [
"一个数组的片断是对同一数据的视图,所以修改它将修改原始数组。"
]
},
{
"cell_type": "code",
"execution_count": 57,
"id": "405b781e-b00e-45e0-99bb-5da1984d6d95",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "1kmtaFHuL9iG",
"outputId": "ee3ab60c-4064-4a9e-b04c-453d3955f1d1",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2\n",
"77\n"
]
}
],
"source": [
"print(a[0, 1])\n",
"b[0, 0] = 77 # b[0, 0] is the same piece of data as a[0, 1]\n",
"print(a[0, 1]) "
]
},
{
"cell_type": "markdown",
"id": "8f5ec9c8-0475-4758-ab0f-512539135edd",
"metadata": {
"id": "_Zcf3zi-L9iI"
},
"source": [
"你也可以把整数索引和片断索引混合起来。但是,这样做会产生一个比原数组秩更低的数组。"
]
},
{
"cell_type": "code",
"execution_count": 58,
"id": "fdccd1c2-0af6-426c-8e10-e61ea8b24013",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 69
},
"id": "G6lfbPuxL9iJ",
"outputId": "a225fe9d-2a29-4e14-a243-2b7d583bd4bc",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[ 1 2 3 4]\n",
" [ 5 6 7 8]\n",
" [ 9 10 11 12]]\n"
]
}
],
"source": [
"# Create the following rank 2 array with shape (3, 4)\n",
"a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])\n",
"print(a)"
]
},
{
"cell_type": "markdown",
"id": "de488e13-2a40-4ff9-8e5a-58eb79e1b083",
"metadata": {
"id": "NCye3NXhL9iL"
},
"source": [
"访问数组中间行的数据的两种方法。将整数索引与分片混合使用会产生一个较低秩的数组,而只使用分片会产生一个与原数组秩相同的数组。"
]
},
{
"cell_type": "code",
"execution_count": 59,
"id": "92c5d9e0-9b34-4e4d-b95d-2a97b4efe24c",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 69
},
"id": "EOiEMsmNL9iL",
"outputId": "ab2ebe48-9002-45a8-9462-fd490b467f40",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[5 6 7 8] (4,)\n",
"[[5 6 7 8]] (1, 4)\n",
"[[5 6 7 8]] (1, 4)\n"
]
}
],
"source": [
"row_r1 = a[1, :] # Rank 1 view of the second row of a \n",
"row_r2 = a[1:2, :] # Rank 2 view of the second row of a\n",
"row_r3 = a[[1], :] # Rank 2 view of the second row of a\n",
"print(row_r1, row_r1.shape)\n",
"print(row_r2, row_r2.shape)\n",
"print(row_r3, row_r3.shape)"
]
},
{
"cell_type": "code",
"execution_count": 60,
"id": "8755f036-6798-4e90-ac7b-39f33f12d2e9",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 104
},
"id": "JXu73pfDL9iN",
"outputId": "6c589b85-e9b0-4c13-a39d-4cd9fb2f41ac",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[ 2 6 10] (3,)\n",
"\n",
"[[ 2]\n",
" [ 6]\n",
" [10]] (3, 1)\n"
]
}
],
"source": [
"# We can make the same distinction when accessing columns of an array:\n",
"col_r1 = a[:, 1]\n",
"col_r2 = a[:, 1:2]\n",
"print(col_r1, col_r1.shape)\n",
"print()\n",
"print(col_r2, col_r2.shape)"
]
},
{
"cell_type": "markdown",
"id": "8a01a977-3298-43a2-b95d-8c20904c9f29",
"metadata": {
"id": "VP3916bOL9iP"
},
"source": [
"整数阵列的索引:当你使用切片法对numpy数组进行索引时,产生的数组视图总是原始数组的一个子数组。相比之下,整数数组索引允许你使用另一个数组的数据来构造任意的数组。"
]
},
{
"cell_type": "code",
"execution_count": 61,
"id": "8f67a0dc-7f00-4618-876e-42d8fef94190",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "TBnWonIDL9iP",
"outputId": "c29fa2cd-234e-4765-c70a-6889acc63573",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[1 4 5]\n",
"[1 4 5]\n"
]
}
],
"source": [
"a = np.array([[1,2], [3, 4], [5, 6]])\n",
"\n",
"# An example of integer array indexing.\n",
"# The returned array will have shape (3,) and \n",
"print(a[[0, 1, 2], [0, 1, 0]])\n",
"\n",
"# The above example of integer array indexing is equivalent to this:\n",
"print(np.array([a[0, 0], a[1, 1], a[2, 0]]))"
]
},
{
"cell_type": "code",
"execution_count": 62,
"id": "21beba4c-b2ef-4431-8c01-835fd6424abc",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "n7vuati-L9iR",
"outputId": "c3e9ba14-f66e-4202-999e-2e1aed5bd631",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[2 2]\n",
"[2 2]\n"
]
}
],
"source": [
"# When using integer array indexing, you can reuse the same\n",
"# element from the source array:\n",
"print(a[[0, 0], [1, 1]])\n",
"\n",
"# Equivalent to the previous integer array indexing example\n",
"print(np.array([a[0, 1], a[0, 1]]))"
]
},
{
"cell_type": "markdown",
"id": "51b52118-7e6d-4ee0-bf6d-63b7c33d675d",
"metadata": {
"id": "kaipSLafL9iU"
},
"source": [
"整数数组索引的一个有用的技巧是从矩阵的每一行中选择或改变一个元素。\n"
]
},
{
"cell_type": "code",
"execution_count": 63,
"id": "ce10fe00-c1d9-40d6-bb16-7d4e551f9cb2",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 86
},
"id": "ehqsV7TXL9iU",
"outputId": "de509c40-4ee4-4b7c-e75d-1a936a3350e7",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[ 1 2 3]\n",
" [ 4 5 6]\n",
" [ 7 8 9]\n",
" [10 11 12]]\n"
]
}
],
"source": [
"# Create a new array from which we will select elements\n",
"a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])\n",
"print(a)"
]
},
{
"cell_type": "code",
"execution_count": 64,
"id": "d0da6687-a4aa-44fb-a887-5f5e8c8ef313",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"id": "pAPOoqy5L9iV",
"outputId": "f812e29b-9218-4767-d3a8-e9854e754e68",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[ 1 6 7 11]\n"
]
}
],
"source": [
"# Create an array of indices\n",
"b = np.array([0, 2, 0, 1])\n",
"\n",
"# Select one element from each row of a using the indices in b\n",
"print(a[np.arange(4), b]) # Prints \"[ 1 6 7 11]\""
]
},
{
"cell_type": "code",
"execution_count": 65,
"id": "061bee12-7c9d-4bbc-a446-23cd62b725ed",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 86
},
"id": "6v1PdI1DL9ib",
"outputId": "89f50f82-de1b-4417-e55c-edbc0ee07584",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[11 2 3]\n",
" [ 4 5 16]\n",
" [17 8 9]\n",
" [10 21 12]]\n"
]
}
],
"source": [
"# Mutate one element from each row of a using the indices in b\n",
"a[np.arange(4), b] += 10\n",
"print(a)"
]
},
{
"cell_type": "markdown",
"id": "590a3bda-0be0-4fa7-808c-cb2d0bfe5baf",
"metadata": {
"id": "kaE8dBGgL9id"
},
"source": [
"布尔数组索引:布尔数组索引可以让你挑选出一个数组中的任意元素。这种类型的索引经常被用来选择一个数组中满足某些条件的元素。"
]
},
{
"cell_type": "code",
"execution_count": 66,
"id": "4b2f3a7d-28c4-4572-aa51-8d56f5087562",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 69
},
"id": "32PusjtKL9id",
"outputId": "8782e8ec-b78d-44d7-8141-23e39750b854",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[False False]\n",
" [ True True]\n",
" [ True True]]\n"
]
}
],
"source": [
"import numpy as np\n",
"\n",
"a = np.array([[1,2], [3, 4], [5, 6]])\n",
"\n",
"bool_idx = (a > 2) # Find the elements of a that are bigger than 2;\n",
" # this returns a numpy array of Booleans of the same\n",
" # shape as a, where each slot of bool_idx tells\n",
" # whether that element of a is > 2.\n",
"\n",
"print(bool_idx)"
]
},
{
"cell_type": "code",
"execution_count": 67,
"id": "bb96e409-bb51-4e52-ac33-ae7b9c3ea002",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "cb2IRMXaL9if",
"outputId": "5983f208-3738-472d-d6ab-11fe85b36c95",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[3 4 5 6]\n",
"[3 4 5 6]\n"
]
}
],
"source": [
"# We use boolean array indexing to construct a rank 1 array\n",
"# consisting of the elements of a corresponding to the True values\n",
"# of bool_idx\n",
"print(a[bool_idx])\n",
"\n",
"# We can do all of the above in a single concise statement:\n",
"print(a[a > 2])"
]
},
{
"cell_type": "markdown",
"id": "73e45a4e-a384-49ee-ae12-806d743d2c12",
"metadata": {
"id": "CdofMonAL9ih"
},
"source": [
"为了简洁起见,我们省略了很多关于numpy数组索引的细节;如果你想知道更多,你应该阅读文档。"
]
},
{
"cell_type": "markdown",
"id": "ddc7baf1-cd19-4f61-96b6-aacbd8f2fa81",
"metadata": {
"id": "jTctwqdQL9ih",
"jp-MarkdownHeadingCollapsed": true,
"tags": []
},
"source": [
"### 数据类型\n",
"\n",
"每个numpy数组都是由相同类型的元素组成的网格。Numpy提供了一大批数字数据类型,你可以用它们来构造数组。当你创建一个数组时,Numpy会尝试猜测一个数据类型,但是构造数组的函数通常也包括一个可选参数来明确指定数据类型。"
]
},
{
"cell_type": "code",
"execution_count": 68,
"id": "3fb87156-0f42-4797-9328-51213ea21af8",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"id": "4za4O0m5L9ih",
"outputId": "2ea4fb80-a4df-43f9-c162-5665895c13ae",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"int64 float64 int64\n"
]
}
],
"source": [
"x = np.array([1, 2]) # Let numpy choose the datatype\n",
"y = np.array([1.0, 2.0]) # Let numpy choose the datatype\n",
"z = np.array([1, 2], dtype=np.int64) # Force a particular datatype\n",
"\n",
"print(x.dtype, y.dtype, z.dtype)"
]
},
{
"cell_type": "markdown",
"id": "82fe5afc-fcc3-49c9-97af-fd2a9372a6cc",
"metadata": {
"id": "RLVIsZQpL9ik"
},
"source": [
"你可以在[文档](http://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html)中阅读关于numpy数据类型的所有信息。"
]
},
{
"cell_type": "markdown",
"id": "32476fb7-f4d1-4011-9cb9-36c9688e01a1",
"metadata": {
"id": "TuB-fdhIL9ik",
"jp-MarkdownHeadingCollapsed": true,
"tags": []
},
"source": [
"### 数组的数学运算\n",
"\n",
"基本数学函数对数组进行元素操作,既可以作为运算符重载,也可以作为numpy模块的函数。"
]
},
{
"cell_type": "code",
"execution_count": 69,
"id": "4d38715d-b81e-4087-961b-5aef0e1253c3",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 86
},
"id": "gHKvBrSKL9il",
"outputId": "a8a924b1-9d60-4b68-8fd3-e4657ae3f08b",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[ 6. 8.]\n",
" [10. 12.]]\n",
"[[ 6. 8.]\n",
" [10. 12.]]\n"
]
}
],
"source": [
"x = np.array([[1,2],[3,4]], dtype=np.float64)\n",
"y = np.array([[5,6],[7,8]], dtype=np.float64)\n",
"\n",
"# Elementwise sum; both produce the array\n",
"print(x + y)\n",
"print(np.add(x, y))"
]
},
{
"cell_type": "code",
"execution_count": 70,
"id": "f39f9dff-c4a7-4520-8429-5b320ac7824d",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 86
},
"id": "1fZtIAMxL9in",
"outputId": "122f1380-6144-4d6c-9d31-f62d839889a2",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[-4. -4.]\n",
" [-4. -4.]]\n",
"[[-4. -4.]\n",
" [-4. -4.]]\n"
]
}
],
"source": [
"# Elementwise difference; both produce the array\n",
"print(x - y)\n",
"print(np.subtract(x, y))"
]
},
{
"cell_type": "code",
"execution_count": 71,
"id": "faceeb11-2c18-4351-a876-d86f2ab5bc3d",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 86
},
"id": "nil4AScML9io",
"outputId": "038c8bb2-122b-4e59-c0a8-a091014fe68e",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[ 5. 12.]\n",
" [21. 32.]]\n",
"[[ 5. 12.]\n",
" [21. 32.]]\n"
]
}
],
"source": [
"# Elementwise product; both produce the array\n",
"print(x * y)\n",
"print(np.multiply(x, y))"
]
},
{
"cell_type": "code",
"execution_count": 72,
"id": "7a9ac1a8-23ae-4b45-bd98-fad524121d5e",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 86
},
"id": "0JoA4lH6L9ip",
"outputId": "12351a74-7871-4bc2-97ce-a508bf4810da",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[0.2 0.33333333]\n",
" [0.42857143 0.5 ]]\n",
"[[0.2 0.33333333]\n",
" [0.42857143 0.5 ]]\n"
]
}
],
"source": [
"# Elementwise division; both produce the array\n",
"# [[ 0.2 0.33333333]\n",
"# [ 0.42857143 0.5 ]]\n",
"print(x / y)\n",
"print(np.divide(x, y))"
]
},
{
"cell_type": "code",
"execution_count": 73,
"id": "10c74001-044f-4e48-a398-dff64e1e62e4",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "g0iZuA6bL9ir",
"outputId": "29927dda-4167-4aa8-fbda-9008b09e4356",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[1. 1.41421356]\n",
" [1.73205081 2. ]]\n"
]
}
],
"source": [
"# Elementwise square root; produces the array\n",
"# [[ 1. 1.41421356]\n",
"# [ 1.73205081 2. ]]\n",
"print(np.sqrt(x))"
]
},
{
"cell_type": "markdown",
"id": "2fe65ae4-0a57-410f-a3f0-e7b202865244",
"metadata": {
"id": "a5d_uujuL9it"
},
"source": [
"注意,与MATLAB不同,`*`是元素乘法,而不是矩阵乘法。我们使用`dot`函数来计算向量的内积,用一个向量乘以一个矩阵,以及乘以矩阵。"
]
},
{
"cell_type": "code",
"execution_count": 74,
"id": "738b4437-fd7b-4061-876d-ae2432d5f59e",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "I3FnmoSeL9iu",
"outputId": "46f4575a-2e5e-4347-a34e-0cc5bd280110",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"219\n",
"219\n"
]
}
],
"source": [
"x = np.array([[1,2],[3,4]])\n",
"y = np.array([[5,6],[7,8]])\n",
"\n",
"v = np.array([9,10])\n",
"w = np.array([11, 12])\n",
"\n",
"# Inner product of vectors; both produce 219\n",
"print(v.dot(w))\n",
"print(np.dot(v, w))"
]
},
{
"cell_type": "markdown",
"id": "8403d5cc-786e-4a09-933e-c0801480d831",
"metadata": {
"id": "vmxPbrHASVeA"
},
"source": [
"你也可以使用`@`运算符,它等同于numpy的`dot`运算符。"
]
},
{
"cell_type": "code",
"execution_count": 75,
"id": "7f1584a4-69ae-4d98-8648-bba0c9fce512",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"id": "vyrWA-mXSdtt",
"outputId": "a9aae545-2c93-4649-b220-b097655955f6",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"219\n"
]
}
],
"source": [
"print(v @ w)"
]
},
{
"cell_type": "code",
"execution_count": 76,
"id": "631c889d-5b47-4050-93ae-2aeccea37a28",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 69
},
"id": "zvUODeTxL9iw",
"outputId": "4093fc76-094f-4453-a421-a212b5226968",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[29 67]\n",
"[29 67]\n",
"[29 67]\n"
]
}
],
"source": [
"# Matrix / vector product; both produce the rank 1 array [29 67]\n",
"print(x.dot(v))\n",
"print(np.dot(x, v))\n",
"print(x @ v)"
]
},
{
"cell_type": "code",
"execution_count": 77,
"id": "bcf85865-0aba-4873-bb12-e01459aed85d",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 121
},
"id": "3V_3NzNEL9iy",
"outputId": "af2a89f9-af5d-47a6-9ad2-06a84b521b94",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[19 22]\n",
" [43 50]]\n",
"[[19 22]\n",
" [43 50]]\n",
"[[19 22]\n",
" [43 50]]\n"
]
}
],
"source": [
"# Matrix / matrix product; both produce the rank 2 array\n",
"# [[19 22]\n",
"# [43 50]]\n",
"print(x.dot(y))\n",
"print(np.dot(x, y))\n",
"print(x @ y)"
]
},
{
"cell_type": "markdown",
"id": "b2d179c8-4696-4ccb-8ab4-32149ba8c196",
"metadata": {
"id": "FbE-1If_L9i0"
},
"source": [
"Numpy提供了许多有用的函数来对数组进行计算,其中最有用的一个是`sum`。"
]
},
{
"cell_type": "code",
"execution_count": 78,
"id": "b4e13eaf-776d-4d58-9d7a-47bf5287d30d",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 69
},
"id": "DZUdZvPrL9i0",
"outputId": "99cad470-d692-4b25-91c9-a57aa25f4c6e",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"10\n",
"[4 6]\n",
"[3 7]\n"
]
}
],
"source": [
"x = np.array([[1,2],[3,4]])\n",
"\n",
"print(np.sum(x)) # Compute sum of all elements; prints \"10\"\n",
"print(np.sum(x, axis=0)) # Compute sum of each column; prints \"[4 6]\"\n",
"print(np.sum(x, axis=1)) # Compute sum of each row; prints \"[3 7]\""
]
},
{
"cell_type": "markdown",
"id": "9115fd7c-075e-4938-9597-8f5b5c6ac332",
"metadata": {
"id": "ahdVW4iUL9i3"
},
"source": [
"除了使用数组计算数学函数外,我们还经常需要对数组中的数据进行重塑或其他操作。这类操作的最简单例子是转置矩阵;要转置矩阵,只需使用数组对象的`T`属性。"
]
},
{
"cell_type": "code",
"execution_count": 79,
"id": "9740187f-5fdb-407b-9333-33820eaf00c2",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 104
},
"id": "63Yl1f3oL9i3",
"outputId": "c75ac7ba-4351-42f8-a09c-a4e0d966ab50",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[1 2]\n",
" [3 4]]\n",
"transpose\n",
" [[1 3]\n",
" [2 4]]\n"
]
}
],
"source": [
"print(x)\n",
"print(\"transpose\\n\", x.T)"
]
},
{
"cell_type": "code",
"execution_count": 80,
"id": "9bd47a46-d582-414d-a09a-6543fac10786",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 104
},
"id": "mkk03eNIL9i4",
"outputId": "499eec5a-55b7-473a-d4aa-9d023d63885a",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[1 2 3]]\n",
"transpose\n",
" [[1]\n",
" [2]\n",
" [3]]\n"
]
}
],
"source": [
"v = np.array([[1,2,3]])\n",
"print(v )\n",
"print(\"transpose\\n\", v.T)"
]
},
{
"cell_type": "markdown",
"id": "d9358129-29e5-4010-a080-f822609bc7f9",
"metadata": {
"id": "REfLrUTcL9i7",
"jp-MarkdownHeadingCollapsed": true,
"tags": []
},
"source": [
"### 广播\n",
"\n",
"广播是一种强大的机制,它允许numpy在进行算术运算时与不同形状的数组一起工作。通常我们有一个较小的数组和一个较大的数组,我们想多次使用较小的数组来对较大的数组进行一些操作。\n",
"\n",
"例如,假设我们想给一个矩阵的每一行添加一个常数向量。"
]
},
{
"cell_type": "code",
"execution_count": 81,
"id": "4c6582f2-457c-45e7-964d-40207fca952b",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 86
},
"id": "WEEvkV1ZL9i7",
"outputId": "3896d03c-3ece-4aa8-f675-aef3a220574d",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[ 2 2 4]\n",
" [ 5 5 7]\n",
" [ 8 8 10]\n",
" [11 11 13]]\n"
]
}
],
"source": [
"# We will add the vector v to each row of the matrix x,\n",
"# storing the result in the matrix y\n",
"x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])\n",
"v = np.array([1, 0, 1])\n",
"y = np.empty_like(x) # Create an empty matrix with the same shape as x\n",
"\n",
"# Add the vector v to each row of the matrix x with an explicit loop\n",
"for i in range(4):\n",
" y[i, :] = x[i, :] + v\n",
"\n",
"print(y)"
]
},
{
"cell_type": "markdown",
"id": "8b4e7921-7cc3-4dc6-95c2-cf6de3060d87",
"metadata": {
"id": "2OlXXupEL9i-"
},
"source": [
"这个方法是可行的;但是当矩阵`x`非常大时,在Python中计算一个显式循环可能会很慢。请注意,将向量`v`添加到矩阵`x`的每一行,相当于通过垂直堆叠多个副本形成矩阵`vv`,然后对`x`和`vv`进行元素求和。 我们可以这样实现这个方法。"
]
},
{
"cell_type": "code",
"execution_count": 82,
"id": "b0c5d546-27b0-4bc9-aaf3-a4a92580e1f2",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 86
},
"id": "vS7UwAQQL9i-",
"outputId": "8621e502-c25d-4a18-c973-886dbfd1df36",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[1 0 1]\n",
" [1 0 1]\n",
" [1 0 1]\n",
" [1 0 1]]\n"
]
}
],
"source": [
"vv = np.tile(v, (4, 1)) # Stack 4 copies of v on top of each other\n",
"print(vv) # Prints \"[[1 0 1]\n",
" # [1 0 1]\n",
" # [1 0 1]\n",
" # [1 0 1]]\""
]
},
{
"cell_type": "code",
"execution_count": 83,
"id": "55015b0b-2113-4265-a933-94f125cc2b05",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 86
},
"id": "N0hJphSIL9jA",
"outputId": "def6a757-170c-43bf-8728-732dfb133273",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[ 2 2 4]\n",
" [ 5 5 7]\n",
" [ 8 8 10]\n",
" [11 11 13]]\n"
]
}
],
"source": [
"y = x + vv # Add x and vv elementwise\n",
"print(y)"
]
},
{
"cell_type": "markdown",
"id": "27c8605f-5c3e-48ce-a7af-fb817860e4b3",
"metadata": {
"id": "zHos6RJnL9jB"
},
"source": [
"Numpy广播允许我们在不实际创建`v`的多个副本的情况下进行这种计算。"
]
},
{
"cell_type": "code",
"execution_count": 84,
"id": "3aa583c2-7776-420a-8a2a-91d721ac6d60",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 86
},
"id": "vnYFb-gYL9jC",
"outputId": "df3bea8a-ad72-4a83-90bb-306b55c6fb93",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[ 2 2 4]\n",
" [ 5 5 7]\n",
" [ 8 8 10]\n",
" [11 11 13]]\n"
]
}
],
"source": [
"import numpy as np\n",
"\n",
"# We will add the vector v to each row of the matrix x,\n",
"# storing the result in the matrix y\n",
"x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])\n",
"v = np.array([1, 0, 1])\n",
"y = x + v # Add v to each row of x using broadcasting\n",
"print(y)"
]
},
{
"cell_type": "markdown",
"id": "65a5ce1e-caac-431d-9bce-bdf2cd8498cf",
"metadata": {},
"source": [
"尽管x的形状是(4, 3),而v的形状是(3,),但由于广播的原因,这行代码`y = x + v`是有效的;这行代码的作用就像v实际上有形状(4, 3)一样,其中每一行都是v的一个副本,并且按元素进行求和。"
]
},
{
"cell_type": "markdown",
"id": "5d2ffca7-fc4f-4588-a6d0-f5b15a11ea80",
"metadata": {},
"source": [
"两个数组一起广播时要遵循这些规则。\n",
"\n",
"1. 如果数组没有相同的秩,则在低秩数组的形状前加上1,直到两个形状具有相同的长度。\n",
"2. 如果两个数组在某一维度上有相同的大小,或者其中一个数组在该维度上有1的大小,则称这两个数组在该维度上兼容。\n",
"3. 如果这两个数组在所有维度上都是兼容的,就可以一起广播。\n",
"4. 在广播之后,每个数组的行为就像它的形状等于两个输入数组形状的元素最大值一样。\n",
"5. 在任何一个维度上,如果一个数组的大小为1,而另一个数组的大小大于1,那么第一个数组的行为就像是沿着该维度复制的一样\n",
"\n",
"尝试阅读[文档](http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html)中的解释来理解。"
]
},
{
"cell_type": "markdown",
"id": "749e267b-bab9-424c-b12c-a56c53450ce6",
"metadata": {},
"source": [
"支持广播的函数被称为通用函数。你可以在[文档](http://docs.scipy.org/doc/numpy/reference/ufuncs.html#available-ufuncs)中找到所有通用函数的列表。\n",
"\n",
"下面是广播的一些应用。"
]
},
{
"cell_type": "code",
"execution_count": 85,
"id": "bd7f1a13-b4cf-4fb5-9a16-7dfeb2f709bd",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 69
},
"id": "EmQnwoM9L9jH",
"outputId": "f59e181e-e2d4-416c-d094-c4d003ce8509",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[ 4 5]\n",
" [ 8 10]\n",
" [12 15]]\n"
]
}
],
"source": [
"# Compute outer product of vectors\n",
"v = np.array([1,2,3]) # v has shape (3,)\n",
"w = np.array([4,5]) # w has shape (2,)\n",
"# To compute an outer product, we first reshape v to be a column\n",
"# vector of shape (3, 1); we can then broadcast it against w to yield\n",
"# an output of shape (3, 2), which is the outer product of v and w:\n",
"\n",
"print(np.reshape(v, (3, 1)) * w)"
]
},
{
"cell_type": "code",
"execution_count": 86,
"id": "46c50dd9-8d9b-4049-a3fa-be0544153703",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "PgotmpcnL9jK",
"outputId": "567763d3-073a-4e3c-9ebe-6c7d2b6d3446",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[2 4 6]\n",
" [5 7 9]]\n"
]
}
],
"source": [
"# Add a vector to each row of a matrix\n",
"x = np.array([[1,2,3], [4,5,6]])\n",
"# x has shape (2, 3) and v has shape (3,) so they broadcast to (2, 3),\n",
"# giving the following matrix:\n",
"\n",
"print(x + v)"
]
},
{
"cell_type": "code",
"execution_count": 87,
"id": "95d83311-482d-402c-ac36-11d790d2e5bb",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "T5hKS1QaL9jK",
"outputId": "5f14ac5c-7a21-4216-e91d-cfce5720a804",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[ 5 6 7]\n",
" [ 9 10 11]]\n"
]
}
],
"source": [
"# Add a vector to each column of a matrix\n",
"# x has shape (2, 3) and w has shape (2,).\n",
"# If we transpose x then it has shape (3, 2) and can be broadcast\n",
"# against w to yield a result of shape (3, 2); transposing this result\n",
"# yields the final result of shape (2, 3) which is the matrix x with\n",
"# the vector w added to each column. Gives the following matrix:\n",
"\n",
"print((x.T + w).T)"
]
},
{
"cell_type": "code",
"execution_count": 88,
"id": "6ffa86e6-9c42-4e5a-b061-da2a2f44d60a",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "JDUrZUl6L9jN",
"outputId": "53e99a89-c599-406d-9fe3-7aa35ae5fb90",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[ 5 6 7]\n",
" [ 9 10 11]]\n"
]
}
],
"source": [
"# Another solution is to reshape w to be a row vector of shape (2, 1);\n",
"# we can then broadcast it directly against x to produce the same\n",
"# output.\n",
"print(x + np.reshape(w, (2, 1)))"
]
},
{
"cell_type": "code",
"execution_count": 89,
"id": "f1cc377a-c728-4313-8174-38d9663939d0",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "VzrEo4KGL9jP",
"outputId": "53c9d4cc-32d5-46b0-d090-53c7db57fb32",
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[ 2 4 6]\n",
" [ 8 10 12]]\n"
]
}
],
"source": [
"# Multiply a matrix by a constant:\n",
"# x has shape (2, 3). Numpy treats scalars as arrays of shape ();\n",
"# these can be broadcast together to shape (2, 3), producing the\n",
"# following array:\n",
"print(x * 2)"
]
},
{
"cell_type": "markdown",
"id": "79790419-5ae6-4fe1-924e-f1aa0b241da2",
"metadata": {},
"source": [
"广播通常会使你的代码更加简洁和快速,所以你应该尽可能地使用它。"
]
},
{
"cell_type": "markdown",
"id": "b44df6e5-3098-485d-b498-84372e82176d",
"metadata": {
"id": "tEINf4bEL9jR",
"jp-MarkdownHeadingCollapsed": true,
"tags": []
},
"source": [
"## Matplotlib"
]
},
{
"cell_type": "markdown",
"id": "e67f32eb-595a-48e8-8b2a-e375d6977a2b",
"metadata": {
"id": "tEINf4bEL9jR",
"jp-MarkdownHeadingCollapsed": true,
"tags": []
},
"source": [
"Matplotlib是一个绘图库。在本节中简要介绍`matplotlib.pyplot`模块,它提供了一个类似于MATLAB的绘图系统。"
]
},
{
"cell_type": "code",
"execution_count": 90,
"id": "bc9e9400-1931-41c6-8016-726cba8df1ac",
"metadata": {
"id": "cmh_7c6KL9jR",
"tags": []
},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"id": "7d0b6894-c2d9-48b9-a201-5ed76192a144",
"metadata": {
"id": "jOsaA5hGL9jS"
},
"source": [
"> 注意:通过运行这个特殊的iPython命令,我们将内联显示图画。"
]
},
{
"cell_type": "code",
"execution_count": 91,
"id": "2e564fc4-9270-45fe-8767-34baff096633",
"metadata": {
"id": "ijpsmwGnL9jT",
"tags": []
},
"outputs": [],
"source": [
"%matplotlib inline"
]
},
{
"cell_type": "markdown",
"id": "fde628ec-c878-440f-8ccb-970af9696791",
"metadata": {
"id": "U5Z_oMoLL9jV"
},
"source": [
"### `plot`绘图\n",
"\n",
"`matplotlib`中最重要的函数是`plot`,它允许你绘制2D数据。下面是一个简单的例子。"
]
},
{
"cell_type": "code",
"execution_count": 92,
"id": "acf23905-201c-4c3c-aa34-8525b857fd3a",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 282
},
"id": "pua52BGeL9jW",
"outputId": "9ac3ee0f-7ff7-463b-b901-c33d21a2b10c",
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"[<matplotlib.lines.Line2D at 0x7fb70b040040>]"
]
},
"execution_count": 92,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Compute the x and y coordinates for points on a sine curve\n",
"x = np.arange(0, 3 * np.pi, 0.1)\n",
"y = np.sin(x)\n",
"\n",
"# Plot the points using matplotlib\n",
"plt.plot(x, y)"
]
},
{
"cell_type": "markdown",
"id": "92fed022-83ba-4151-80ad-f3b44047bf51",
"metadata": {
"id": "9W2VAcLiL9jX"
},
"source": [
"只需做一点额外的工作,我们就可以很容易地一次绘制多条线,并添加一个标题、图例和轴标签。"
]
},
{
"cell_type": "code",
"execution_count": 93,
"id": "f5e9b070-b853-417e-b588-ca7deeabe6e8",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 312
},
"id": "TfCQHJ5AL9jY",
"outputId": "fdb9c033-0f06-4041-a69d-a0f3a54c7206",
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.legend.Legend at 0x7fb70b30c9d0>"
]
},
"execution_count": 93,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAksAAAHFCAYAAADi7703AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAACrlElEQVR4nOzdd3wUdfrA8c/upldIQgqQhAAp9N57CyLYUMGG5x2i3p39vPP4efY7PT1PudOznOWwIioWVER6k95bEkIPkJCEkF53d35/TGaTAMkmkGS2PO/Xa1872czOPpsy+8y3PF+DoigKQgghhBDikox6ByCEEEII4cgkWRJCCCGEaIAkS0IIIYQQDZBkSQghhBCiAZIsCSGEEEI0QJIlIYQQQogGSLIkhBBCCNEASZaEEEIIIRogyZIQQgghRAMkWRJCNGjLli3ccMMNxMTE4O3tTUREBMOGDeMPf/hDnf3Gjh3L2LFj9QmylcyfPx+DwcDx48cbtf/69euZMWMGHTp0wMvLi+DgYIYPH85bb71FSUlJi8RoMBh45plnWuTYQrgrD70DEEI4rh9//JFrr72WsWPH8vLLLxMVFUVmZibbt2/n888/55///Kdt3zfffFPHSB3P008/zXPPPcfw4cN5/vnn6dKlC6WlpWzcuJFnnnmGQ4cO8dprrzX7627atImOHTs2+3GFcGcGWRtOCFGfMWPGcPr0aVJTU/HwqHttZbVaMRrdq3F6/vz5/PrXv+bYsWN06tSp3v2+/PJLZsyYwezZs3n33XcxGAx1vl9UVMSmTZtITk5u4YiFEM3Bvc50QogmOXfuHGFhYRclSsBFidKF3XDHjx/HYDDwyiuv8OqrrxIXF0dAQADDhg1j8+bNFx1v+/btXHvttYSEhODj40O/fv344osvGhXns88+y5AhQwgJCSEoKIj+/fvz/vvvc+G1YKdOnZg2bRpLly6lf//++Pr6kpSUxAcffHDRMTdv3syIESPw8fGhffv2zJ07l6qqqkbF89xzz9G2bVv+/e9/X5QoAQQGBtZJlMrLy5k7dy5xcXF4eXnRoUMHfv/735Ofn1/neatWrWLs2LGEhobi6+tLTEwMN954I6WlpbZ9LuyG07oOV69ezW9/+1vCwsIIDQ1l+vTpnDlz5qLYFi5cyLBhw/D39ycgIIDJkyeza9euRr1vIVyVJEtCiHoNGzaMLVu28OCDD7Jly5ZGJwu1/ec//2H58uXMmzePTz/9lJKSEq6++moKCgps+6xevZoRI0aQn5/P22+/zXfffUffvn2ZOXMm8+fPt/sax48f59577+WLL77g66+/Zvr06TzwwAM8//zzF+27Z88e/vCHP/DII4/w3Xff0bt3b2bPns26dets+xw8eJAJEyaQn5/P/Pnzefvtt9m1axd//etf7caSmZnJ/v37SU5Oxs/Pz+7+iqJw/fXX88orrzBr1ix+/PFHHn30UT788EPGjx9PRUWF7T1OnToVLy8vPvjgA5YuXcrf//53/P39qaystPs6d999N56ennz22We8/PLLrFmzhjvuuKPOPi+88AK33nor3bt354svvuDjjz+mqKiIUaNGcfDgQbuvIYTLUoQQoh65ubnKyJEjFUABFE9PT2X48OHKiy++qBQVFdXZd8yYMcqYMWNsXx87dkwBlF69eilms9n2+NatWxVAWbBgge2xpKQkpV+/fkpVVVWdY06bNk2JiopSLBZLo2O2WCxKVVWV8txzzymhoaGK1Wq1fS82Nlbx8fFRTpw4YXusrKxMCQkJUe69917bYzNnzlR8fX2VrKws22Nms1lJSkpSAOXYsWP1vv7mzZsVQPnzn//cqHiXLl2qAMrLL79c5/GFCxcqgPLf//5XURRF+eqrrxRA2b17d4PHA5Snn37a9vX//vc/BVB+97vf1dnv5ZdfVgAlMzNTURRFOXnypOLh4aE88MADdfYrKipSIiMjlRkzZjTq/QjhiqRlSQhRr9DQUNavX8+2bdv4+9//znXXXcehQ4eYO3cuvXr1Ijc31+4xpk6dislksn3du3dvAE6cOAHA4cOHSU1N5fbbbwfAbDbbbldffTWZmZmkpaU1+BqrVq1i4sSJBAcHYzKZ8PT05KmnnuLcuXNkZ2fX2bdv377ExMTYvvbx8SEhIcEWD6gtXRMmTCAiIsL2mMlkYubMmXbfb1OtWrUKgLvuuqvO4zfffDP+/v6sXLnSFreXlxf33HMPH374IUePHm3S61x77bV1vr7w9/Dzzz9jNpu588476/wOfHx8GDNmDGvWrLmMdyeEa5BkSQhh18CBA3n88cf58ssvOXPmDI888gjHjx/n5Zdftvvc0NDQOl97e3sDUFZWBsDZs2cBeOyxx/D09Kxz+93vfgfQYFK2detW2/ifd999l19++YVt27bxxBNP1Hmd+uLRYqq937lz54iMjLxov0s9diEtETt27JjdfbXX8vDwoF27dnUeNxgMREZGcu7cOQC6dOnCihUrCA8P5/e//z1dunShS5cu/Otf/2rU6zT29zBo0KCLfg8LFy5sVGIshKuS0gFCiCbx9PTk6aef5rXXXmP//v1XfLywsDAA5s6dy/Tp0y+5T2JiYr3P//zzz/H09OSHH37Ax8fH9vi333572TGFhoaSlZV10eOXeuxCUVFR9OrVi2XLllFaWmp33FJoaChms5mcnJw6CZOiKGRlZTFo0CDbY6NGjWLUqFFYLBa2b9/O66+/zsMPP0xERAS33HJLE97hxbTfw1dffUVsbOwVHUsIVyMtS0KIemVmZl7y8ZSUFADat29/xa+RmJhIfHw8e/bsYeDAgZe8BQYG1vt8g8GAh4dHna6+srIyPv7448uOady4caxcudLW2gJgsVhYuHBho57/5JNPcv78eR588MGLZuQBFBcXs2zZMgAmTJgAwCeffFJnn0WLFlFSUmL7fm0mk4khQ4bwn//8B4CdO3c27o01YPLkyXh4eHDkyJF6fw9CuCtpWRJC1Gvy5Ml07NiRa665hqSkJKxWK7t37+af//wnAQEBPPTQQ83yOu+88w5Tpkxh8uTJ3HXXXXTo0IG8vDxSUlLYuXMnX375Zb3PnTp1Kq+++iq33XYb99xzD+fOneOVV16xdTNdjr/85S8sXryY8ePH89RTT+Hn58d//vOfRlfdvvnmm3nyySd5/vnnSU1NZfbs2bailFu2bOGdd95h5syZJCcnM2nSJCZPnszjjz9OYWEhI0aMYO/evTz99NP069ePWbNmAfD222+zatUqpk6dSkxMDOXl5baSBxMnTrzs96rp1KkTzz33HE888QRHjx7lqquuom3btpw9e5atW7fi7+/Ps88+e8WvI4RT0nuEuRDCcS1cuFC57bbblPj4eCUgIEDx9PRUYmJilFmzZikHDx6ss299s+H+8Y9/XHRcLpixpSiKsmfPHmXGjBlKeHi44unpqURGRirjx49X3n77bbtxfvDBB0piYqLi7e2tdO7cWXnxxReV999//6KZa7GxscrUqVMvev6FsSuKovzyyy/K0KFDFW9vbyUyMlL54x//qPz3v/+1OxuutrVr1yo33XSTEhUVpXh6eipBQUHKsGHD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",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"y_sin = np.sin(x)\n",
"y_cos = np.cos(x)\n",
"\n",
"# Plot the points using matplotlib\n",
"plt.plot(x, y_sin)\n",
"plt.plot(x, y_cos)\n",
"plt.xlabel('x axis label')\n",
"plt.ylabel('y axis label')\n",
"plt.title('Sine and Cosine')\n",
"plt.legend(['Sine', 'Cosine'])"
]
},
{
"cell_type": "markdown",
"id": "8a1be4c8-3eb0-418a-811d-711a8c307e6d",
"metadata": {
"id": "R5IeAY03L9ja"
},
"source": [
"### `subplots` 绘图\n",
"\n",
"你可以使用subplot函数在同一个图中绘制一组不同的图形。下面是一个例子。"
]
},
{
"cell_type": "code",
"execution_count": 94,
"id": "608674d3-388e-42ec-aa89-cdb89f442b46",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 281
},
"id": "dM23yGH9L9ja",
"outputId": "14dfa5ea-f453-4da5-a2ee-fea0de8f72d9",
"tags": []
},
"outputs": [
{
"data": {
"image/png": "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zc2tOueVV16huLiY0aNHVy1S99tvv93UGi9CCCGEsHyyPYAQQgghVGe267xUh7+7mKz3IoQQQpiPv39v38w1FYsrL/n5lYtayXRpIYQQwvzk5+ej011/w1aLu21kMBhISUnBzc2t2hep+nsNmaSkJLklpQL5+atLfv7qkp+/uuTnb3yKopCfn09AQAA2NtefT2RxV15sbGyoW7euUV/D3d1d/vGqSH7+6pKfv7rk568u+fkb142uuPxNlqgUQgghhFmR8iKEEEIIsyLl5RZotVqmTZsm2xGoRH7+6pKfv7rk568u+fmbFosbsCuEEEIIyyZXXoQQQghhVqS8CCGEEMKsSHkRQgghhFmR8iKEEEIIsyLl5SYtXLiQ4OBgHB0diYyMZMeOHWpHshqzZs2ibdu2uLm54ePjw4ABA0hISFA7llWaNWsWGo2GcePGqR3FaiQnJ/Poo4/i5eWFs7MzERERREdHqx3LKlRUVDB16lSCg4NxcnIiJCSE6dOnYzAY1I5m9aS83ISVK1cybtw4pkyZQkxMDF26dKFXr14kJiaqHc0qbNu2jeeee449e/awefNmKioqiIqKorCwUO1oVmX//v0sWbKEFi1aqB3FamRnZ9O5c2fs7e355ZdfOHbsGO+99x4eHh5qR7MKs2fPZvHixXz88cfEx8czZ84c3n33XT766CO1o1k9mSp9E9q3b0/r1q1ZtGhR1bGwsDAGDBjArFmzVExmnTIyMvDx8WHbtm107dpV7ThWoaCggNatW7Nw4ULefvttIiIimD9/vtqxLN6rr77KX3/9JVd6VdK3b198fX1ZunRp1bHBgwfj7OzM8uXLVUwm5MrLDZSVlREdHU1UVNQVx6Oioti1a5dKqaxbbm4uAJ6enionsR7PPfccffr04e67777huXFxcTzxxBNVt1ldXV1p3bo1c+bMISsrq9qz1a9fn8cff7zav64p+PHHH2nTpg0PPPAAPj4+tGrVik8//VTtWFbjjjvu4I8//uDEiRMAHDp0iJ07d9K7d2+VkwmL25ixumVmZqLX6/H19b3iuK+vL2lpaSqlsl6KojBhwgTuuOMOwsPD1Y5jFb777jsOHjzI/v37b3jup59+yujRowkNDeXll1+madOmlJeXc+DAARYvXszu3btZu3ZtteZbu3atxW6Ud+bMGRYtWsSECROYPHky+/btY+zY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",
"text/plain": [
"<Figure size 640x480 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Compute the x and y coordinates for points on sine and cosine curves\n",
"x = np.arange(0, 3 * np.pi, 0.1)\n",
"y_sin = np.sin(x)\n",
"y_cos = np.cos(x)\n",
"\n",
"# Set up a subplot grid that has height 2 and width 1,\n",
"# and set the first such subplot as active.\n",
"plt.subplot(2, 1, 1)\n",
"\n",
"# Make the first plot\n",
"plt.plot(x, y_sin)\n",
"plt.title('Sine')\n",
"\n",
"# Set the second subplot as active, and make the second plot.\n",
"plt.subplot(2, 1, 2)\n",
"plt.plot(x, y_cos)\n",
"plt.title('Cosine')\n",
"\n",
"# Show the figure.\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"id": "34673720-8427-4f00-baf7-46036206c1cc",
"metadata": {
"jp-MarkdownHeadingCollapsed": true,
"slideshow": {
"slide_type": "-"
},
"tags": []
},
"source": [
"## PyTorch 基础操作"
]
},
{
"cell_type": "markdown",
"id": "21b0466c-fb43-4762-9166-2dd12c1034f2",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"首先,我们导入`torch`。请注意,虽然它被称为PyTorch,但是代码中使用`torch`而不是`pytorch`"
]
},
{
"cell_type": "code",
"execution_count": 95,
"id": "7072100b-254f-41d6-b9e8-d27a37a25ce1",
"metadata": {
"origin_pos": 5,
"tab": [
"pytorch"
]
},
"outputs": [],
"source": [
"import torch"
]
},
{
"cell_type": "markdown",
"id": "ecd36dfc-bc63-4547-97a5-38711e5b02d3",
"metadata": {
"tags": []
},
"source": [
"### 基础数据操作"
]
},
{
"cell_type": "markdown",
"id": "8e3d4848-c8d4-4355-afbc-b5c2d998fc6b",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"张量表示由一个数值组成的数组,这个数组可能有多个维度"
]
},
{
"cell_type": "code",
"execution_count": 96,
"id": "00494188-41fc-43a5-9d11-3bd6484a0c2c",
"metadata": {
"origin_pos": 12,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])"
]
},
"execution_count": 96,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x = torch.arange(12)\n",
"x"
]
},
{
"cell_type": "markdown",
"id": "d9bdb205-33a2-4768-a536-a36fc9756b7d",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"可以通过张量的`shape`属性来访问张量(沿每个轴的长度)的*形状*\n",
"和张量中元素的总数"
]
},
{
"cell_type": "code",
"execution_count": 97,
"id": "257a7b06-2f7c-404f-b83e-5380b61bc16d",
"metadata": {
"origin_pos": 15,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"torch.Size([12])"
]
},
"execution_count": 97,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x.shape"
]
},
{
"cell_type": "code",
"execution_count": 98,
"id": "8c9f723b-e97c-4bc3-a306-065c328bbd82",
"metadata": {
"origin_pos": 18,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"12"
]
},
"execution_count": 98,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x.numel()"
]
},
{
"cell_type": "markdown",
"id": "6c16fb49-9a2b-4078-9a14-465b3f0b4775",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"要想改变一个张量的形状而不改变元素数量和元素值,可以调用`reshape`函数"
]
},
{
"cell_type": "code",
"execution_count": 99,
"id": "705f5253-c52b-4f7d-97b9-f144f8401919",
"metadata": {
"origin_pos": 21,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[ 0, 1, 2, 3],\n",
" [ 4, 5, 6, 7],\n",
" [ 8, 9, 10, 11]])"
]
},
"execution_count": 99,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X = x.reshape(3, 4)\n",
"X"
]
},
{
"cell_type": "markdown",
"id": "1d098270-4487-41a4-b7e3-b49e0034fd09",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"使用全0、全1、其他常量,或者从特定分布中随机采样的数字"
]
},
{
"cell_type": "code",
"execution_count": 100,
"id": "2c571f46-7e48-481b-8a5e-4e2dd2f2aa96",
"metadata": {
"origin_pos": 25,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[[0., 0., 0., 0.],\n",
" [0., 0., 0., 0.],\n",
" [0., 0., 0., 0.]],\n",
"\n",
" [[0., 0., 0., 0.],\n",
" [0., 0., 0., 0.],\n",
" [0., 0., 0., 0.]]])"
]
},
"execution_count": 100,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"torch.zeros((2, 3, 4))"
]
},
{
"cell_type": "code",
"execution_count": 101,
"id": "9950f805-d1e4-4948-b541-3c7de8b5a8e0",
"metadata": {
"origin_pos": 29,
"slideshow": {
"slide_type": "-"
},
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[[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.]]])"
]
},
"execution_count": 101,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"torch.ones((2, 3, 4))"
]
},
{
"cell_type": "code",
"execution_count": 102,
"id": "e7262b6f-2be5-47e4-b115-66c9579fdd69",
"metadata": {
"origin_pos": 33,
"slideshow": {
"slide_type": "-"
},
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[-1.6135, 0.3384, -0.1105, -0.2204],\n",
" [ 1.8458, 1.0330, 1.3026, -1.9075],\n",
" [-0.9892, -1.4300, 0.3078, -0.5878]])"
]
},
"execution_count": 102,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"torch.randn(3, 4)"
]
},
{
"cell_type": "markdown",
"id": "de202a80-5b43-45c5-bd4f-13ff3f3dc89a",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"通过提供包含数值的Python列表(或嵌套列表),来为所需张量中的每个元素赋予确定值"
]
},
{
"cell_type": "code",
"execution_count": 103,
"id": "e0ea9924-9165-4c67-9b76-a2bd10ea5127",
"metadata": {
"origin_pos": 37,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[2, 1, 4, 3],\n",
" [1, 2, 3, 4],\n",
" [4, 3, 2, 1]])"
]
},
"execution_count": 103,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])"
]
},
{
"cell_type": "markdown",
"id": "770bc9b0-79a3-479b-b862-304376c754ae",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"常见的标准算术运算符(`+`、`-`、`*`、`/`和`**`)都可以被升级为按元素运算"
]
},
{
"cell_type": "code",
"execution_count": 104,
"id": "f77581a2-5e47-4f8a-bf07-5371ae54a7b5",
"metadata": {
"origin_pos": 41,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"(tensor([ 3., 4., 6., 10.]),\n",
" tensor([-1., 0., 2., 6.]),\n",
" tensor([ 2., 4., 8., 16.]),\n",
" tensor([0.5000, 1.0000, 2.0000, 4.0000]),\n",
" tensor([ 1., 4., 16., 64.]))"
]
},
"execution_count": 104,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x = torch.tensor([1.0, 2, 4, 8])\n",
"y = torch.tensor([2, 2, 2, 2])\n",
"x + y, x - y, x * y, x / y, x ** y"
]
},
{
"cell_type": "markdown",
"id": "c40e3586-87a1-4608-a50b-7a4cb3874e57",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"“按元素”方式可以应用更多的计算"
]
},
{
"cell_type": "code",
"execution_count": 105,
"id": "5b38f2a0-73ce-4318-9306-d359ce3ffa7f",
"metadata": {
"origin_pos": 45,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([2.7183e+00, 7.3891e+00, 5.4598e+01, 2.9810e+03])"
]
},
"execution_count": 105,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"torch.exp(x)"
]
},
{
"cell_type": "markdown",
"id": "e08e33e3-008b-439d-9faf-fc86475eb1c4",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"我们也可以把多个张量*连结*(concatenate)在一起"
]
},
{
"cell_type": "code",
"execution_count": 106,
"id": "e3cd445d-03a1-4143-84af-dcbe10af8612",
"metadata": {
"origin_pos": 49,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"(tensor([[ 0., 1., 2., 3.],\n",
" [ 4., 5., 6., 7.],\n",
" [ 8., 9., 10., 11.],\n",
" [ 2., 1., 4., 3.],\n",
" [ 1., 2., 3., 4.],\n",
" [ 4., 3., 2., 1.]]),\n",
" tensor([[ 0., 1., 2., 3., 2., 1., 4., 3.],\n",
" [ 4., 5., 6., 7., 1., 2., 3., 4.],\n",
" [ 8., 9., 10., 11., 4., 3., 2., 1.]]))"
]
},
"execution_count": 106,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X = torch.arange(12, dtype=torch.float32).reshape((3,4))\n",
"Y = torch.tensor(\n",
" [[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])\n",
"torch.cat((X, Y), dim=0), torch.cat((X, Y), dim=1)"
]
},
{
"cell_type": "markdown",
"id": "10a03ef1-696f-4e85-ac98-beda0866d211",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"通过*逻辑运算符*构建二元张量"
]
},
{
"cell_type": "code",
"execution_count": 107,
"id": "3dea4fba-f0ec-4e46-8a42-903e82814e03",
"metadata": {
"origin_pos": 52,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[False, True, False, True],\n",
" [False, False, False, False],\n",
" [False, False, False, False]])"
]
},
"execution_count": 107,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X == Y"
]
},
{
"cell_type": "markdown",
"id": "a1d0b36e-7dc6-4c37-a2c7-910e54e19b88",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"对张量中的所有元素进行求和,会产生一个单元素张量"
]
},
{
"cell_type": "code",
"execution_count": 108,
"id": "c46d5a6f-101c-4645-9040-4a69796eefb7",
"metadata": {
"origin_pos": 54,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor(66.)"
]
},
"execution_count": 108,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X.sum()"
]
},
{
"cell_type": "markdown",
"id": "553ec6c4-7890-4f41-834f-b096d0d54d53",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"即使形状不同,我们仍然可以通过调用\n",
"*广播机制*(broadcasting mechanism)来执行按元素操作"
]
},
{
"cell_type": "code",
"execution_count": 109,
"id": "e153c79d-3787-4a77-9ffe-281f12f8d9df",
"metadata": {
"origin_pos": 58,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"(tensor([[0],\n",
" [1],\n",
" [2]]),\n",
" tensor([[0, 1]]))"
]
},
"execution_count": 109,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = torch.arange(3).reshape((3, 1))\n",
"b = torch.arange(2).reshape((1, 2))\n",
"a, b"
]
},
{
"cell_type": "code",
"execution_count": 110,
"id": "83ab5c84-7920-427d-b175-77d8fec956f1",
"metadata": {
"origin_pos": 61,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[0, 1],\n",
" [1, 2],\n",
" [2, 3]])"
]
},
"execution_count": 110,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a + b"
]
},
{
"cell_type": "markdown",
"id": "1d9b5a62-173f-4c23-b8df-181968dd84ab",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"可以用`[-1]`选择最后一个元素,可以用`[1:3]`选择第二个和第三个元素"
]
},
{
"cell_type": "code",
"execution_count": 111,
"id": "d64d3449-137f-41d9-9d1b-5d08f917c876",
"metadata": {
"origin_pos": 63,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"(tensor([ 8., 9., 10., 11.]),\n",
" tensor([[ 4., 5., 6., 7.],\n",
" [ 8., 9., 10., 11.]]))"
]
},
"execution_count": 111,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X[-1], X[1:3]"
]
},
{
"cell_type": "markdown",
"id": "2105d701-9c03-4110-94d6-deb5f9462af4",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"除读取外,我们还可以通过指定索引来将元素写入矩阵"
]
},
{
"cell_type": "code",
"execution_count": 112,
"id": "685988cd-f1aa-4a45-beec-55aa248e36d6",
"metadata": {
"origin_pos": 66,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[ 0., 1., 2., 3.],\n",
" [ 4., 5., 9., 7.],\n",
" [ 8., 9., 10., 11.]])"
]
},
"execution_count": 112,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X[1, 2] = 9\n",
"X"
]
},
{
"cell_type": "markdown",
"id": "a49aaed7-4dd8-4431-8fe3-7caaddf0cc58",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"为多个元素赋值相同的值,我们只需要索引所有元素,然后为它们赋值"
]
},
{
"cell_type": "code",
"execution_count": 113,
"id": "cd8257b2-02c8-4883-bc5c-c5266bb90be1",
"metadata": {
"origin_pos": 69,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[12., 12., 12., 12.],\n",
" [12., 12., 12., 12.],\n",
" [ 8., 9., 10., 11.]])"
]
},
"execution_count": 113,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X[0:2, :] = 12\n",
"X"
]
},
{
"cell_type": "markdown",
"id": "933dd1bd-77cd-4461-a0e7-6adfc64bcc77",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"运行一些操作可能会导致为新结果分配内存"
]
},
{
"cell_type": "code",
"execution_count": 114,
"id": "b96e0f82-ff89-4032-b1b0-bf2da61f9445",
"metadata": {
"origin_pos": 72,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 114,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"before = id(Y)\n",
"Y = Y + X\n",
"id(Y) == before"
]
},
{
"cell_type": "markdown",
"id": "cdb325dc-833f-4999-a1ca-6b01b62d0d33",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"执行原地操作"
]
},
{
"cell_type": "code",
"execution_count": 115,
"id": "f2cf3cbf-6a17-4c16-82dc-d1bbb1f18c10",
"metadata": {
"origin_pos": 77,
"tab": [
"pytorch"
]
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"id(Z): 140424225140144\n",
"id(Z): 140424225140144\n"
]
}
],
"source": [
"Z = torch.zeros_like(Y)\n",
"print('id(Z):', id(Z))\n",
"Z[:] = X + Y\n",
"print('id(Z):', id(Z))"
]
},
{
"cell_type": "markdown",
"id": "e1879c6c-338c-4207-a9eb-86a5dc7d6c7e",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"如果在后续计算中没有重复使用`X`,\n",
"我们也可以使用`X[:] = X + Y`或`X += Y`来减少操作的内存开销"
]
},
{
"cell_type": "code",
"execution_count": 116,
"id": "d9898688-95b8-4397-96cf-f6f2c59ff828",
"metadata": {
"origin_pos": 81,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 116,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"before = id(X)\n",
"X += Y\n",
"id(X) == before"
]
},
{
"cell_type": "markdown",
"id": "0d0d06a1-04ea-4979-952e-fb5b23a0db34",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"转换为NumPy张量(`ndarray`)"
]
},
{
"cell_type": "code",
"execution_count": 117,
"id": "66091d08-8118-49ff-9950-e38322c494e0",
"metadata": {
"origin_pos": 87,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"(numpy.ndarray, torch.Tensor)"
]
},
"execution_count": 117,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A = X.numpy()\n",
"B = torch.tensor(A)\n",
"type(A), type(B)"
]
},
{
"cell_type": "markdown",
"id": "0d7b1448-f79b-4b14-a5c5-1996fdcb6a0d",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"将大小为1的张量转换为Python标量"
]
},
{
"cell_type": "code",
"execution_count": 118,
"id": "21495ba4-a629-4a4c-ab74-a96e7185e649",
"metadata": {
"origin_pos": 91,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"(tensor([3.5000]), 3.5, 3.5, 3)"
]
},
"execution_count": 118,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = torch.tensor([3.5])\n",
"a, a.item(), float(a), int(a)"
]
},
{
"cell_type": "markdown",
"id": "8e5412a5-ea69-4f6c-b2b2-ddc920f54259",
"metadata": {
"jp-MarkdownHeadingCollapsed": true,
"slideshow": {
"slide_type": "-"
},
"tags": []
},
"source": [
"## 数据预处理\n",
"\n",
"首选创建一个人工数据集,并存储在CSV(逗号分隔值)文件"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "e4b52867-b4f3-46db-92a6-64b92efc2074",
"metadata": {
"origin_pos": 1,
"tab": [
"pytorch"
],
"tags": []
},
"outputs": [],
"source": [
"import os\n",
"\n",
"os.makedirs(os.path.join('..', 'data'), exist_ok=True)\n",
"data_file = os.path.join('..', 'data', 'house_tiny.csv')\n",
"with open(data_file, 'w') as f:\n",
" f.write('NumRooms,Alley,Price\\n')\n",
" f.write('NA,Pave,127500\\n')\n",
" f.write('2,NA,106000\\n')\n",
" f.write('4,NA,178100\\n')\n",
" f.write('NA,NA,140000\\n')"
]
},
{
"cell_type": "markdown",
"id": "0f5a8d30-86f9-490f-b907-ac86447750d8",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"从创建的CSV文件中加载原始数据集"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "7aecf9e4-b604-415f-a5bb-83414e1ccc6a",
"metadata": {
"origin_pos": 3,
"tab": [
"pytorch"
],
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" NumRooms Alley Price\n",
"0 NaN Pave 127500\n",
"1 2.0 NaN 106000\n",
"2 4.0 NaN 178100\n",
"3 NaN NaN 140000\n"
]
}
],
"source": [
"import pandas as pd\n",
"\n",
"data = pd.read_csv(data_file)\n",
"print(data)"
]
},
{
"cell_type": "markdown",
"id": "b79dde6b-c078-4ec1-a9c3-5f1cedd07025",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"为了处理缺失的数据,典型的方法包括*插值法*和*删除法*,\n",
"这里,我们将考虑插值法"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "317fa349-cad0-4cc9-9315-85d2c8a22fa0",
"metadata": {
"origin_pos": 5,
"tab": [
"pytorch"
],
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" NumRooms Alley\n",
"0 3.0 Pave\n",
"1 2.0 NaN\n",
"2 4.0 NaN\n",
"3 3.0 NaN\n"
]
}
],
"source": [
"inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]\n",
"# 用同一列的均值替换“NaN”项\n",
"inputs['NumRooms'] = inputs['NumRooms'].fillna(inputs['NumRooms'].mean())\n",
"print(inputs)"
]
},
{
"cell_type": "markdown",
"id": "43d3dae7-20bc-4955-a323-ec40e087b927",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"对于`inputs`中的类别值或离散值,我们将“NaN”视为一个类别"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "9f23dd19-079e-4514-9edc-e7167813fd78",
"metadata": {
"origin_pos": 7,
"tab": [
"pytorch"
],
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" NumRooms Alley_Pave Alley_nan\n",
"0 3.0 1 0\n",
"1 2.0 0 1\n",
"2 4.0 0 1\n",
"3 3.0 0 1\n"
]
}
],
"source": [
"# get_dummies 是 pandas 实现one hot encode的方式。\n",
"inputs = pd.get_dummies(inputs, dummy_na=True).astype('float32')\n",
"print(inputs)"
]
},
{
"cell_type": "markdown",
"id": "f5a23184-6c3d-492b-94ce-4872167d8d6e",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"现在`inputs`和`outputs`中的所有条目都是数值类型,它们可以转换为张量格式"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "f5bda8b1-62c2-4518-b7ba-575b668af195",
"metadata": {
"origin_pos": 10,
"tab": [
"pytorch"
],
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"(tensor([[3., 1., 0.],\n",
" [2., 0., 1.],\n",
" [4., 0., 1.],\n",
" [3., 0., 1.]], dtype=torch.float64),\n",
" tensor([127500, 106000, 178100, 140000]))"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import torch\n",
"\n",
"X, y = torch.tensor(inputs.values), torch.tensor(outputs.values)\n",
"X, y"
]
},
{
"cell_type": "markdown",
"id": "31feece7-041b-41b9-9cf7-f36a8bd5b614",
"metadata": {
"jp-MarkdownHeadingCollapsed": true,
"slideshow": {
"slide_type": "-"
},
"tags": []
},
"source": [
"## 查阅文档"
]
},
{
"cell_type": "markdown",
"id": "7ce98e3a-903e-4215-ab19-3376d4f79ecb",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"查询随机数生成模块中的所有属性"
]
},
{
"cell_type": "code",
"execution_count": 124,
"id": "0645a1ad-92fc-4ed0-a97d-3d44b9dabc5e",
"metadata": {
"attributes": {
"classes": [],
"id": "",
"n": "1"
},
"origin_pos": 6,
"tab": [
"pytorch"
]
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['AbsTransform', 'AffineTransform', 'Bernoulli', 'Beta', 'Binomial', 'CatTransform', 'Categorical', 'Cauchy', 'Chi2', 'ComposeTransform', 'ContinuousBernoulli', 'CorrCholeskyTransform', 'CumulativeDistributionTransform', 'Dirichlet', 'Distribution', 'ExpTransform', 'Exponential', 'ExponentialFamily', 'FisherSnedecor', 'Gamma', 'Geometric', 'Gumbel', 'HalfCauchy', 'HalfNormal', 'Independent', 'IndependentTransform', 'Kumaraswamy', 'LKJCholesky', 'Laplace', 'LogNormal', 'LogisticNormal', 'LowRankMultivariateNormal', 'LowerCholeskyTransform', 'MixtureSameFamily', 'Multinomial', 'MultivariateNormal', 'NegativeBinomial', 'Normal', 'OneHotCategorical', 'OneHotCategoricalStraightThrough', 'Pareto', 'Poisson', 'PowerTransform', 'RelaxedBernoulli', 'RelaxedOneHotCategorical', 'ReshapeTransform', 'SigmoidTransform', 'SoftmaxTransform', 'SoftplusTransform', 'StackTransform', 'StickBreakingTransform', 'StudentT', 'TanhTransform', 'Transform', 'TransformedDistribution', 'Uniform', 'VonMises', 'Weibull', 'Wishart', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'bernoulli', 'beta', 'biject_to', 'binomial', 'categorical', 'cauchy', 'chi2', 'constraint_registry', 'constraints', 'continuous_bernoulli', 'dirichlet', 'distribution', 'exp_family', 'exponential', 'fishersnedecor', 'gamma', 'geometric', 'gumbel', 'half_cauchy', 'half_normal', 'identity_transform', 'independent', 'kl', 'kl_divergence', 'kumaraswamy', 'laplace', 'lkj_cholesky', 'log_normal', 'logistic_normal', 'lowrank_multivariate_normal', 'mixture_same_family', 'multinomial', 'multivariate_normal', 'negative_binomial', 'normal', 'one_hot_categorical', 'pareto', 'poisson', 'register_kl', 'relaxed_bernoulli', 'relaxed_categorical', 'studentT', 'transform_to', 'transformed_distribution', 'transforms', 'uniform', 'utils', 'von_mises', 'weibull', 'wishart']\n"
]
}
],
"source": [
"import torch\n",
"\n",
"print(dir(torch.distributions))"
]
},
{
"cell_type": "markdown",
"id": "02436ac3-7d34-4530-9870-4f8fc6ce9b57",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"查看张量`ones`函数的用法"
]
},
{
"cell_type": "code",
"execution_count": 125,
"id": "15555ccb-2632-4944-9640-cb699be1985a",
"metadata": {
"origin_pos": 10,
"tab": [
"pytorch"
]
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Help on built-in function ones in module torch:\n",
"\n",
"ones(...)\n",
" ones(*size, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) -> Tensor\n",
" \n",
" Returns a tensor filled with the scalar value `1`, with the shape defined\n",
" by the variable argument :attr:`size`.\n",
" \n",
" Args:\n",
" size (int...): a sequence of integers defining the shape of the output tensor.\n",
" Can be a variable number of arguments or a collection like a list or tuple.\n",
" \n",
" Keyword arguments:\n",
" out (Tensor, optional): the output tensor.\n",
" dtype (:class:`torch.dtype`, optional): the desired data type of returned tensor.\n",
" Default: if ``None``, uses a global default (see :func:`torch.set_default_tensor_type`).\n",
" layout (:class:`torch.layout`, optional): the desired layout of returned Tensor.\n",
" Default: ``torch.strided``.\n",
" device (:class:`torch.device`, optional): the desired device of returned tensor.\n",
" Default: if ``None``, uses the current device for the default tensor type\n",
" (see :func:`torch.set_default_tensor_type`). :attr:`device` will be the CPU\n",
" for CPU tensor types and the current CUDA device for CUDA tensor types.\n",
" requires_grad (bool, optional): If autograd should record operations on the\n",
" returned tensor. Default: ``False``.\n",
" \n",
" Example::\n",
" \n",
" >>> torch.ones(2, 3)\n",
" tensor([[ 1., 1., 1.],\n",
" [ 1., 1., 1.]])\n",
" \n",
" >>> torch.ones(5)\n",
" tensor([ 1., 1., 1., 1., 1.])\n",
"\n"
]
}
],
"source": [
"help(torch.ones)"
]
},
{
"cell_type": "markdown",
"id": "2bd40831-b4ee-49c1-8184-52254f7e8f46",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"运行一个快速测试"
]
},
{
"cell_type": "code",
"execution_count": 126,
"id": "6a89c5b8-4e64-41b8-b01d-6051364ccc6f",
"metadata": {
"origin_pos": 14,
"tab": [
"pytorch"
],
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([1., 1., 1., 1.])"
]
},
"execution_count": 126,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"torch.ones(4)"
]
},
{
"cell_type": "markdown",
"id": "dc1d218c-74fb-43f5-8881-7722ca7e8966",
"metadata": {
"jp-MarkdownHeadingCollapsed": true,
"slideshow": {
"slide_type": "-"
},
"tags": []
},
"source": [
"## 线性代数\n",
"\n",
"标量由只有一个元素的张量表示"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "cd2c4055-b850-49c0-a143-f62bd7e3bcd9",
"metadata": {
"origin_pos": 2,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"(tensor(5.), tensor(6.), tensor(1.5000), tensor(9.))"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import torch\n",
"\n",
"x = torch.tensor(3.0)\n",
"y = torch.tensor(2.0)\n",
"\n",
"x + y, x * y, x / y, x**y"
]
},
{
"cell_type": "markdown",
"id": "b73e9dd4-ec21-4a0e-8af0-b7852469586f",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"你可以将向量视为标量值组成的列表"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "169ea89c-53cf-4fa6-b236-cda1804d625f",
"metadata": {
"origin_pos": 6,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([0, 1, 2, 3])"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x = torch.arange(4)\n",
"x"
]
},
{
"cell_type": "markdown",
"id": "3c18f409-b2b5-4738-b4b5-711aa3b6e818",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"通过张量的索引来访问任一元素"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "5f10955c-3598-40a0-9072-0bd1d87a9cf6",
"metadata": {
"origin_pos": 10,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor(3)"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x[3]"
]
},
{
"cell_type": "markdown",
"id": "2c7e94dd-4b55-43bd-a171-1a51e78ed383",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"访问张量的长度"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "98ec7ee3-391a-473b-832a-1abf3a22fd24",
"metadata": {
"origin_pos": 14,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"4"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"len(x)"
]
},
{
"cell_type": "markdown",
"id": "a8b9cf99-a1ca-4594-ab14-96cafa4913b3",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"只有一个轴的张量,形状只有一个元素"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "d5b671d0-a3c8-4712-a998-3d8f8a824dfb",
"metadata": {
"origin_pos": 18,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"torch.Size([4])"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x.shape"
]
},
{
"cell_type": "markdown",
"id": "5cec9658-5806-4b33-83ef-e1d65cb65698",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"通过指定两个分量$m$和$n$来创建一个形状为$m \\times n$的矩阵"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "eab50756-2d26-4ae3-9af8-cb4a9ba510cc",
"metadata": {
"origin_pos": 22,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[ 0, 1, 2, 3],\n",
" [ 4, 5, 6, 7],\n",
" [ 8, 9, 10, 11],\n",
" [12, 13, 14, 15],\n",
" [16, 17, 18, 19]])"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A = torch.arange(20).reshape(5, 4)\n",
"A"
]
},
{
"cell_type": "markdown",
"id": "96ad2a88-6be4-4813-8784-c46394e573ea",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"矩阵的转置"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "a89cb776-5542-486a-85d4-5d8bb023f583",
"metadata": {
"origin_pos": 26,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[ 0, 4, 8, 12, 16],\n",
" [ 1, 5, 9, 13, 17],\n",
" [ 2, 6, 10, 14, 18],\n",
" [ 3, 7, 11, 15, 19]])"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A.T"
]
},
{
"cell_type": "markdown",
"id": "89520f25-eddb-4c50-8698-a9fb2f8a9ae0",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"*对称矩阵*(symmetric matrix)$\\mathbf{A}$等于其转置:$\\mathbf{A} = \\mathbf{A}^\\top$"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "a259368d-ef93-40e3-98a9-cea2ca08170c",
"metadata": {
"origin_pos": 30,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[1, 2, 3],\n",
" [2, 0, 4],\n",
" [3, 4, 5]])"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"B = torch.tensor([[1, 2, 3], [2, 0, 4], [3, 4, 5]])\n",
"B"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "99671df2-5907-40ac-a2dc-ddbcae7fb15b",
"metadata": {
"origin_pos": 34,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[True, True, True],\n",
" [True, True, True],\n",
" [True, True, True]])"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"B == B.T"
]
},
{
"cell_type": "markdown",
"id": "77eaa5c0-d699-4c71-96b6-341ff9a2f786",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"就像向量是标量的推广,矩阵是向量的推广一样,我们可以构建具有更多轴的数据结构"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "553c27c6-7879-474d-b629-579cbff9a51d",
"metadata": {
"origin_pos": 38,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[[ 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]]])"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X = torch.arange(24).reshape(2, 3, 4)\n",
"X"
]
},
{
"cell_type": "markdown",
"id": "ed485a8f-84fd-4b04-b919-d337d4f0e7b3",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"给定具有相同形状的任意两个张量,任何按元素二元运算的结果都将是相同形状的张量"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "ab355da7-80f1-4873-9861-69a06fec9ff4",
"metadata": {
"origin_pos": 42,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"(tensor([[ 0., 1., 2., 3.],\n",
" [ 4., 5., 6., 7.],\n",
" [ 8., 9., 10., 11.],\n",
" [12., 13., 14., 15.],\n",
" [16., 17., 18., 19.]]),\n",
" tensor([[ 0., 2., 4., 6.],\n",
" [ 8., 10., 12., 14.],\n",
" [16., 18., 20., 22.],\n",
" [24., 26., 28., 30.],\n",
" [32., 34., 36., 38.]]))"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A = torch.arange(20, dtype=torch.float32).reshape(5, 4)\n",
"B = A.clone()\n",
"A, A + B"
]
},
{
"cell_type": "markdown",
"id": "2bafc57a-4995-4499-bcee-b26fb036081a",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"两个矩阵的按元素乘法称为*Hadamard积*(Hadamard product)(数学符号$\\odot$)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "81a6e1d8-fa9f-4652-8adc-5a2a0ff139ea",
"metadata": {
"origin_pos": 46,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[ 0., 1., 4., 9.],\n",
" [ 16., 25., 36., 49.],\n",
" [ 64., 81., 100., 121.],\n",
" [144., 169., 196., 225.],\n",
" [256., 289., 324., 361.]])"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A * B"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "dfb1beb4-70c2-414f-b3e7-9b174610711d",
"metadata": {
"origin_pos": 50,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"(tensor([[[ 2, 3, 4, 5],\n",
" [ 6, 7, 8, 9],\n",
" [10, 11, 12, 13]],\n",
" \n",
" [[14, 15, 16, 17],\n",
" [18, 19, 20, 21],\n",
" [22, 23, 24, 25]]]),\n",
" torch.Size([2, 3, 4]))"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = 2\n",
"X = torch.arange(24).reshape(2, 3, 4)\n",
"a + X, (a * X).shape"
]
},
{
"cell_type": "markdown",
"id": "c64a6a97-a816-4c59-b822-0335764d4542",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"计算其元素的和"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "f94739c3-2d30-4c9b-9187-3bfa32e0cf59",
"metadata": {
"origin_pos": 54,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"(tensor([0., 1., 2., 3.]), tensor(6.))"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x = torch.arange(4, dtype=torch.float32)\n",
"x, x.sum()"
]
},
{
"cell_type": "markdown",
"id": "6c275f66-ded8-400e-8584-664ee1d383de",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"表示任意形状张量的元素和"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "c1251c8a-e9de-49b5-aad3-fa3d249272b3",
"metadata": {
"origin_pos": 58,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"(torch.Size([5, 4]), tensor(190.))"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A.shape, A.sum()"
]
},
{
"cell_type": "markdown",
"id": "440e1d56-71c3-4e40-a1e9-e75156ccc879",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"指定张量沿哪一个轴来通过求和降低维度"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "7d853e52-6c4b-4859-b795-04a7ec943bd6",
"metadata": {
"origin_pos": 62,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"(tensor([40., 45., 50., 55.]), torch.Size([4]))"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A_sum_axis0 = A.sum(axis=0)\n",
"A_sum_axis0, A_sum_axis0.shape"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "b25421d8-1f82-4599-829e-5395d8a3874e",
"metadata": {
"origin_pos": 66,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"(tensor([ 6., 22., 38., 54., 70.]), torch.Size([5]))"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A_sum_axis1 = A.sum(axis=1)\n",
"A_sum_axis1, A_sum_axis1.shape"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "d165e4b0-2e2d-4c8e-9023-20cf64b6cd16",
"metadata": {
"origin_pos": 70,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor(190.)"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A.sum(axis=[0, 1])"
]
},
{
"cell_type": "markdown",
"id": "c9e64a9b-0e01-4c69-9861-70ec4dffe99e",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"一个与求和相关的量是*平均值*(mean或average)"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "8a336685-119e-42c5-8cc2-672635751655",
"metadata": {
"origin_pos": 74,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"(tensor(9.5000), tensor(9.5000))"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A.mean(), A.sum() / A.numel()"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "393ba1e4-585a-481a-8cd1-875e2f810ef6",
"metadata": {
"origin_pos": 78,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"(tensor([ 8., 9., 10., 11.]), tensor([ 8., 9., 10., 11.]))"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A.mean(axis=0), A.sum(axis=0) / A.shape[0]"
]
},
{
"cell_type": "markdown",
"id": "970d1362-391d-4415-bfc3-d0a77c19e44d",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"计算总和或均值时保持轴数不变"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "dde63412-60a3-4836-ae9d-7704f12da74d",
"metadata": {
"origin_pos": 82,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[ 6.],\n",
" [22.],\n",
" [38.],\n",
" [54.],\n",
" [70.]])"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sum_A = A.sum(axis=1, keepdims=True)\n",
"sum_A"
]
},
{
"cell_type": "markdown",
"id": "fb401f55-958f-442e-8a61-c5ecd9beadba",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"通过广播将`A`除以`sum_A`"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "fac69c9b-be07-4e92-9c5c-7b9625f12bc1",
"metadata": {
"origin_pos": 86,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[0.0000, 0.1667, 0.3333, 0.5000],\n",
" [0.1818, 0.2273, 0.2727, 0.3182],\n",
" [0.2105, 0.2368, 0.2632, 0.2895],\n",
" [0.2222, 0.2407, 0.2593, 0.2778],\n",
" [0.2286, 0.2429, 0.2571, 0.2714]])"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A / sum_A"
]
},
{
"cell_type": "markdown",
"id": "767cda68-07c3-4ba9-82c5-7f62b1cf136c",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"某个轴计算`A`元素的累积总和"
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "81e39538-8f7f-4298-b7e7-64497f3a6bac",
"metadata": {
"origin_pos": 90,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[ 0., 1., 2., 3.],\n",
" [ 4., 6., 8., 10.],\n",
" [12., 15., 18., 21.],\n",
" [24., 28., 32., 36.],\n",
" [40., 45., 50., 55.]])"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A.cumsum(axis=0)"
]
},
{
"cell_type": "markdown",
"id": "e5b9654a-7e34-410c-86aa-96b1c5614bb8",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"点积是相同位置的按元素乘积的和"
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "4619a1d3-de75-4752-8812-32e6fac520cf",
"metadata": {
"origin_pos": 94,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"(tensor([0., 1., 2., 3.]), tensor([1., 1., 1., 1.]), tensor(6.))"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"y = torch.ones(4, dtype = torch.float32)\n",
"x, y, torch.dot(x, y)"
]
},
{
"cell_type": "markdown",
"id": "c4fb029c-aa94-429d-a589-43092d7feb85",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"我们可以通过执行按元素乘法,然后进行求和来表示两个向量的点积"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "c077fa90-787e-481f-b1ca-24996d86ab2a",
"metadata": {
"origin_pos": 98,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor(6.)"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"torch.sum(x * y)"
]
},
{
"cell_type": "markdown",
"id": "d311339c-f0bb-47b7-b42b-6d73fceb085c",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"矩阵向量积$\\mathbf{A}\\mathbf{x}$是一个长度为$m$的列向量,\n",
"其第$i$个元素是点积$\\mathbf{a}^\\top_i \\mathbf{x}$"
]
},
{
"cell_type": "code",
"execution_count": 26,
"id": "d8d3d075-5b31-4d6c-8b9f-e543742b44ab",
"metadata": {
"origin_pos": 105,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"(torch.Size([5, 4]), torch.Size([4]), tensor([ 14., 38., 62., 86., 110.]))"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A.shape, x.shape, torch.mv(A, x)"
]
},
{
"cell_type": "markdown",
"id": "207c6561-32ac-4af4-bb9e-b46dc9a64f42",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"我们可以将矩阵-矩阵乘法$\\mathbf{AB}$看作是简单地执行$m$次矩阵-向量积,并将结果拼接在一起,形成一个$n \\times m$矩阵"
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "284ba1a4-57aa-48d8-aa85-2500c08c25ac",
"metadata": {
"origin_pos": 109,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[ 6., 6., 6.],\n",
" [22., 22., 22.],\n",
" [38., 38., 38.],\n",
" [54., 54., 54.],\n",
" [70., 70., 70.]])"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"B = torch.ones(4, 3)\n",
"torch.mm(A, B)"
]
},
{
"cell_type": "markdown",
"id": "3d9c2b99-2e75-48a6-b466-e9ba55feac2e",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"$L_2$*范数*是向量元素平方和的平方根:\n",
"$$\\|\\mathbf{x}\\|_2 = \\sqrt{\\sum_{i=1}^n x_i^2}$$"
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "e0f0052d-5bad-4846-9d8c-34f7a242cc11",
"metadata": {
"origin_pos": 113,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor(5.)"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"u = torch.tensor([3.0, -4.0])\n",
"torch.norm(u)"
]
},
{
"cell_type": "markdown",
"id": "498deac2-e4e8-4713-8a87-bb31f93b59e4",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"$L_1$范数,它表示为向量元素的绝对值之和:\n",
"$$\\|\\mathbf{x}\\|_1 = \\sum_{i=1}^n \\left|x_i \\right|$$"
]
},
{
"cell_type": "code",
"execution_count": 29,
"id": "fe719ad6-ad4e-4485-9d92-af4781facd3c",
"metadata": {
"origin_pos": 117,
"tab": [
"pytorch"
]
},
"outputs": [
{
"data": {
"text/plain": [
"tensor(7.)"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"torch.abs(u).sum()"
]
},
{
"cell_type": "markdown",
"id": "8634d5e6-8428-4abd-b989-73f9d6108dc7",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"矩阵\n",
"的*Frobenius范数*(Frobenius norm)是矩阵元素平方和的平方根:\n",
"$$\\|\\mathbf{X}\\|_F = \\sqrt{\\sum_{i=1}^m \\sum_{j=1}^n x_{ij}^2}$$"
]
},
{
"cell_type": "code",
"execution_count": 30,
"id": "ccca6045-62c6-42ec-b760-4413065bf1be",
"metadata": {
"origin_pos": 121,
"tab": [
"pytorch"
],
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"tensor(6.)"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"torch.norm(torch.ones((4, 9)))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.16"
}
},
"nbformat": 4,
"nbformat_minor": 5
}