创建名为web的vue项目
1 | vue create web |
创建项目的选择如下:
启动项目
1 | cd web |
1 | npm run serve |
使用窗口按钮来启动项目
安装ant-design-vue
1 | npm install ant-design-vue@2.0.0-rc.3 --save |
adj.(计算机系统或图像)沉浸式虚拟现实的
n.自拍照
n.(舞台的)背景幕布,周围陪衬景物
n.透镜,镜片,(眼球的)晶状体
n.服装,衣服,演出服;v.给······提供服装
n.旗袍
n.曲线;v.(使)弯曲
adj.优雅的,俊美的,简练的
n.讲述者,幕后解说员
n.摄影家
adj,殷勤的;(像)骑士一般的,豪侠的
adj.战争的,军事的
发生,像雨后春笋般涌现
修身的
连衣裙
笔记来源:Java疯狂讲义
输入机制:允许程序读取外部数据(包括硬盘等存储设备上的数据)、用户输入数据等
输出机制:允许程序记录运行状态,将程序数据输出到磁盘、光盘等
Java的IO操作通过java.io
包下的类和接口来实现,主要包括输入、输出两种IO流。每种输入输出流又可以分为字节流和字符流。Java的IO流还使用了装饰器设计模式,他将IO流分为 底层节点流
和 上层处理流
。
File类是java.io包下与平台无关的文件和目录,如果希望在程序中操作文件和目录,可以通过它来实现:新建、删除、重命名文件和目录。File不能访问文件内容本身,须通过输入输出流来操作文件内容本身。
1 | File file = new File("/Users/mr.stark/Desktop/test.txt"); |
1 | //文件是否存在 |
1 | //文件最后修改时间 |
1 | //创建 |
1 | //创建FIle对象对应的目录 |
有一点需注意,当使用相对路径的File对象来获取父路径时可能引起错误。
File类的 list()
方法可以接收一个FilenameFilter参数,通过该参数可以列出符合条件的文件。
1 | File f = new File("."); |
Java的IO流是实现输入、输出的基础。Java中将不同的输入输出源(键盘、文件、网络连接)抽象描述为“流”(stream),通过“流”的方式允许Java程序使用相同的方式访问不同的输入输出源。
由于Java提供了IO流的抽象,所以开发者可以使用一致的IO代码去读写不同的IO流结点
这里的输入输出是从程序运行所在内存角度来划分的,如数据从内存到硬盘,就是一个输出流。
Java的输入流主要由InputStream
和Reader
作为基类,而输出流则由OutputStream
和Writer
作为基类
两者几乎一样,字节流操作的数据单元是8位的字节,字符流操作的数据单元是16位的字节。
实际上,Java使用处理流来包装节点流是一种典型的装饰器设计模式
Java将所有设备里的有序数据抽象成流模型,简化了输入输出处理,理解了流的概念模型也就理解了JavaIO。
Java的IO流共涉及到40多个类,彼此之间有着非常紧密的联系。Java的40多个类都是从下面四个抽象基类派生出来的:
对于InputStream和Reader而言,可以将输入设备看成一个“水管”,水管里的“水滴”依次排列,如下图:
输出流与输入流类似,它们将输出设备抽象成一个“水管”,只是这个水管里没有任何“水滴”,如下图:
还有一个就是 处理流
,能够嫁接在任何已存在的流的基础之上,这就允许使用相同的Java代码来访问不同的输入输出设备的数据流,如下所示:
InputStream和Reader是所有输入流的抽象基类,是所有其他输入流的模板。
int read()
从输入流中读取单个字节,返回读取的字节数据
int read(byte[] b)
从输入流中读取最多读取b.length()
个字节的数据,将其存储在字节数组b中,返回实际读取的字节数
int read(byte[] b, int off, int len)
从输入流中最多读取len个字节的数据,将其存储在字节数组b中(并不是从数组起点开始,而是从off位置开始),返回实际读取的字节数
int read()
从输入流中读取单个字符,返回读取的字符数据
int read(char[] b)
从输入流中读取最多读取b.length()
个字符的数据,将其存储在字符数组b中,返回实际读取的字符数
int read(char[] b, int off, int len)
从输入流中最多读取len个字符的数据,将其存储在字符数组b中(并不是从数组起点开始,而是从off位置开始),返回实际读取的字符数
这两个基类的基本功能是一样的,从输入流中取数据:
InputStream和Reader都是抽象类,本身不能创建实例,但它们有一种用于读取文件的输入流:FIleInputStream和FileReader,它们都是节点流,下面代码展示了使用FileInputStream读取自身的效果:
1 | public class FileInputStreamTest { |
void writer(int c)
将指定的字节/字符输出到输出流中去,c即可以代表字节,也可以代表字符
void writer(byte[]/char[] buff)
将字节/字符数组输出到输出流中去
void writer(byte[]/char[] buff, int off, int len)
将字节/字符数组从off位置开始,长度为len的字节/字符数组输出到指定输出流中去
void writer(String str)
将字符串输出到输出流中
void writer(String str, int off, int len)
将str字符串从off位置开始,长度为len的字符输出到指定流中去
代码如下:
1 | public class FileOutputStream { |
使用Java的IO流执行输出时,不要忘记关闭输出流,关闭输出流除了可以保障流的物理资源被回收之外,还可以将输出流缓冲区里的数据flush到物理节点里面(close方法执行之前会自动执行flush方法)
如果希望直接输出字符串的内容,使用Writer会更好。
上述四个基类用起来会比较繁琐,这时候可以使用处理流。
处理流
可以隐藏底层设备上节点流的差异,对外提供一个更加方便的输入输出方法。使用处理流的思路是:使用处理流来包装节点流,通过处理流来执行输入输出的功能,让节点流与底层设备交互。
识别处理流:只要流的构造器参数不是一个物理节点,而是已经存在的流。
如下使用PrintStream处理流来包装OutputStream:
1 | public class PrintStreamTest { |
PrintStream非常强大,像之前的
System.out
就是PrintStream类型。一般来说,如果要输出文本,都应该包装成PrintStream后输出。在使用了处理流包装了底层节点之后,关闭输入输出资源时,只需关闭最上层的处理流即可。
下面将其按功能分类:
通常来说,字节流的功能比字符流更加强大,因为计算机里的数据都是二进制存放,字节流可以处理所有的二进制文件—如果用字节流来处理文本文件,将字节转化为字符增加了编程难度。故:文本内容–>字符流;二进制内容–>字节流。
输入/输出体系中还提供了两个转换流,这两个转换流用于将字节流转换成字符流:
InputStreamReader
将字节输入流转化成字符输入流
PutputStreamWriter
将字节输出流转化为字符输出流
Java不提供将字符流转化为字节流的转换流,因为如果一个流是字符流,它用起来会更方便,没必要转换成为字节流。
下面以获取键盘输入为例:Java使用System.in
代表标准输入(键盘输入),这个标准类是InputStream
的实例,用起来不方便,于是使用InputStreamReader
将其包装为字符输入流。普通的Reader
读取输入内容时依然不太方便,将InputStreamReader
包装为BufferedReader
,可以使用它的readline()
一次读取一行内容。
1 | public class KeyinTest { |
在输入/输出体系中,有两个特殊的流与众不同,就是PushbackInputStream
和PushbackReader
,提供了如下三个方法:
void unread(byte[]/char[] buf)
将一个字节/字符数组内容推到缓冲区里,从而允许重复读取刚刚读取的内容。
void unread(byte[]/char[] buf, int off, int len)
将一个字节/字符数组内容(从off开始,长度为len)推到缓冲区里,从而允许重复读取刚刚读取的内容。
void unread(int b)
将一个字节/字符推到缓冲区里,从而允许重复读取刚刚读取的内容。
这俩推回输入流都带有一个推回缓冲区,当调用unread()
方法时,系统会将指定的数组内容推回到该缓冲区,当调用read()
方法时,总是会先从该推回缓冲区读取,只有完全读取了推回缓冲区的内容但还没有装满read()
所需的数组大小时才会从原输入流中读取:
如下示例代码(将指定内容推回缓冲区,再调用read()
方法读取缓冲区的部分内容):
1 | public class PushbackTest { |
Java的标准输入、输出分别通过System.in
和System.out
来代表,默认情况下分别代表键盘和显示器。
在System类里提供了如下三个重定向标准标准输入/输出的方法,如下:
//重定向“标准”错误输入流
static void setErr(PrintStream err)
1
2
3
4
- ```java
//重定向“标准”输入流
static void setIn(InputStream in)
//重定向“标准”输出流
static void setOut(PrintStream out)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
下面通过程序通过重定向标准输出流将` System.out `重定向到文件输出:
```java
public class RedirectOut {
public static void main(String[] args) {
try {
//一次性创建PrintStream输出流
PrintStream ps = new PrintStream(new FileOutputStream("out.txt"));
//将标准输出重定向到ps输出流
System.setOut(ps);
//向标准输出输出一个字符串
System.out.println("疯狂Java讲义");
//向标准输出输出一个对象
System.out.println(new RedirectOut());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
上述代码将系统的标准输出重定向到该PrintStream输出流,咱们再来看一个将` System.in `重定向栗子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class RedirectIn {
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("/Users/mr.stark/Desktop/test.java");
//将标准输入重定向到fis输入流
System.setIn(fis);
//使用System.in创建Scanner对象,用于获取标准输入
Scanner sc = new Scanner(System.in);
//增加下面一行将回车作为分隔符
sc.useDelimiter("\n");
//判断是否有下一个输入项
while (sc.hasNext()) {
//输出输入项
System.out.println(sc.next());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
Runtime对象的 exec()
可以运行平台上的其他程序,该方法产生一个Process对象,代表该Java程序启动的子进程。该类提供了以下三个方法用于让程序与其他子进程通信:
//获取子进程的输入流
public abstract InputStream getInputStream();
1
2
3
4
- ```java
//获取子进程的错误流
public abstract InputStream getErrorStream();
//获取子进程的输出流
public abstract OutputStream getOutputStream();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
> 此处输入流、输出流很容易让人混淆,如果试图让子进程读取程序中的数据,应该用输入流还是输出流?不是输入流,而输出流。要站在Java程序员的角度考虑问题,要让Java程序把数据输出到子进程中,所以是输出流。
下面的这个程序演示了读取其他进程的输出信息:
```java
public class ReadFromProcess {
public static void main(String[] args) throws IOException {
//运行javac命令,返回运行该命令的子进程
Process p = Runtime.getRuntime().exec("javac");
//以p进程的错误流创建BufferedReader对象,这个错误流对本程序是输入流,对启动的进程是输出流
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
//循环读取p进程的错误输出
String buff;
while ( (buff = br.readLine()) != null ) {
System.out.println(buff);
}
}
}
上面程序中的 Process p = Runtime.getRuntime().exec("javac");
启动了javac程序。
对象序列化的目标是将对象保存在磁盘中或者在网络中传输。对象序列化机制允许把内存中的Java对象转换成与平台无关的二进制流,从而允许把这种二进制流持久的保存在磁盘上或者通过网络传输。其他程序获得了这种二进制流之后可以将其恢复为Java对象。
序列化机制允许将实现序列化的Java对象转化为字节序列(从而方便存储在磁盘上或者在网络节点间传输),以备以后恢复成Java对象。序列化机制就使得对象可以脱离程序运行而独立存在。
对象序列化(Serialize)只将一个Java对象写入IO流中,与之对应,反序列化(Deserialize)则指从IO流中恢复对象。
Java9增强了对象序列化机制,允许对读入的序列化数据进行过滤,这种过滤可在反序列化之前对数据进行校验,从而提高程序健壮性和安全性。要让某个类是可序列化的,需实现下面两个接口之间的一个:
Java很多类已经实现了Serializable,这是一个标记接口,实现该接口无需实现任何方法,他只是表明该类的实例是可以序列化的。
所有可能在网络上传输的对象的类都应该是可序列化的,否则程序将出现异常,如RMI(Remote Method Invoke,即远程方法调用)过程中的参数与返回值;所有需要保存到磁盘里的对象的类都必须可以序列化。例如Web应用中需要保存到HttpSession或ServletContext属性的Java对象。
一旦某个类实现了Serializable接口,他就是可序列化的,下面通过程序来看看:
1 | //---------------------------------------Person对象--------------------------------------- |
如果Person没有实现Serializable接口,则会报错: java.io.NotSerializableException
异常。
接下来我们尝试将 object.txt
恢复为一个Java对象:
1 | public class ReadObject { |
上述代码使用 Person p = (Person) ois.readObject();
读取了Java对象。须注意的是:反序列读的仅仅是Java对象的数据,而非Java类,因此采用反序列化恢复数据时必须提供Java对象所属的Class文件,否则会引发ClassNotFoundException
异常。
当一个可序列化对象有多个父类时(包括直接父类和间接父类),这些父类要么有无参构造器,要么也是可序列化的-否则会抛出InvalidClassException
异常。如果父类只是带有无参数的构造器,则父类中的成员变量是不会序列化到二进制流中去的。
前面介绍的 Person
类的两个成员分别是String和int类型,如果一个类的成员变量类型不是基本类型或者String类型,而是另一个引用类型,那么这个引用类必须是可序列化的,否则拥有该类型成员变量的类也是不可序列化的。
1 | @Data |
当程序序列化一个Teacher对象时,如果Teacher对象持有一个Person对象的引用,为了在反序列化时可以正常恢复Teacher对象,程序会将该Person对象也进行序列化。
现在假设有下面的一种特殊情况:程序中有两个Teacher对象,他们的student实例变量引用到同一个Person对象,该Person对象还有一个引用变量引用它,代码如下:
1 | Person per = new Person("孙悟空", 500); |
上面三个对象在内存的情况如下:
这里产生了一个问题:
如果先序列化t1对象,则系统将该t1对象所引用的Person对象一起序列化;如果系统再序列化t2对象,系统将一样会再序列化该t2对象,并且将再次序列化该t2对象所引用的Person对象;如果程序再显式序列化per对象,系统会再次序列化Person对象。这个过程似乎会向输出流输出三个Person对象。
如果系统向输出流输出了三个Person对象,那么后果就是当程序从输出流中反序列化这些对象时,将会得到三个Person对象,从而引起t1和t2引用的Person对象不是同一个—这也就违背了Java序列化机制的初衷。
所以,Java序列化机制采用了一种特殊的序列化算法:
因此根据上面的算法:当第二次第三次序列化Persin对象时,程序不会再将对象转化成为字节数组,而是仅仅输出一个序列化编号,假设有如下序列化代码:
1 | //创建一个ObjectOutputStream输出流 |
序列化后的磁盘存储文件如下图所示:
由于程序序列化机制使然:如果程序多次序列化同一个对象,只有第一次序列化会将对象转化为字节数组输出,后面再进行序列化,只是输出前面序列化的编号。
使用Java序列化机制序列化可变对象需要注意,只有第一次调用
writeObject()
方法来输出对象才会将对象转换为字节序列,并写入到ObjectOutPutStream;在后面程序即使发生了改变,再次调用writeObject()
方法输出该对象时,该对象依然不会改变。
Java9为 ObjectInputStream
增加了 setObjectInputFilter(ObjectInputFilter filter)
和 getObjectInputFilter()
两个方法,第一个方法为对象输入流设置过滤器,。当程序通过 ObjectInputStream
反序列化对象时,会自动触发用于检查序列化数据是否有效。
使用 checkInfo()
方法检查序列化数据会有三种情况:
Status.REJECTED
:拒绝恢复 Status.ALLOWED
:允许恢复 Status.UNDECIDED
:未决定状态,程序继续执行 ObjectInputStream
根据 ObjectInputFilter
的状态来决定是否执行反序列化,下面上代码:
1 | public class FilterTest { |
上述程序设置了 ObjectINputFilter
过滤器(程序使用Lambda表达式创建过滤器),重写了 checkInfo()
方法。通过过滤器可以使程序更加安全、健壮。
在一些场景下,我们不希望序列化实例变量的某些数据,或者某个实例变量的类型是不可序列化的,因此不希望进行递归序列化,以免引发 NotSerializableException
异常
递归序列化:系统会把该对象的所有实例变量依次进行序列化,如果某个实例变量引用了另一个对象,则被引用的对象也会进行序列化;如果被引用的对象的实例变量又引用了其他对象,则此被引用的对象也会进行序列化(无限套娃)。
在实例变量前面用 transient
修饰,就可以指定Java序列化时无需理会该变量。注意: transient
只能修饰实例变量,不可修饰Java程序中其他成分!
使用 transient
虽然简单,但是他会将实例变量完全隔离在序列化机制之外,导致在反序列化恢复Java对象时无法取得该实例变量的值。于是咱们再来看看另外一种序列化机制,通过这种方式,我们程序员可以完全掌控序列化过程。在序列化和反序列化中需要特殊处理的类应当提供如下特殊签名的方法以实现自定义序列化:
//写入特定类的实例状态
private void writeObject(java.io.ObjectOutputStream out)
1
2
3
4
- ```java
//从流中读取并恢复对象的实例变量
private void readObject(java.io.ObjectInputStream in)
//当序列流不完整的时候,可以调用该方法来正确的初始化反序列的对象
private void readObjectNoData()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
下面的Person类提供了` writeObject `和` readObject`方法,将name的字符序列反转后写入字节数组,恢复时再进行一次反转。看下面的代码(在Person类中加入以下代码):
```java
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
//将name实例变量值反转后写入二进制流
out.writeObject(new StringBuffer(name).reverse());
out.writeInt(age);
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
//将读取的字符串反转后赋给name实例变量
this.name = ((StringBuffer) in.readObject()).reverse().toString();
this.age = in.readInt();
}
注意:
writeObject()
存储实例变脸的顺序应当与readObject()
顺序一致,否则将不能正确恢复该实例变量。
这种序列化方法更彻底,这种方法甚至可以替换掉序列化的对象。如需使用这种方法,则需提供和如下特殊方法:
1 | private Object writeReplace() |
依然以上面的Person为例,在类中加入以下方法:
1 | private Object writeReplace() { |
当反序列化该对象时,应当强转为 ArrayList
,实际上程序在序列化的并非 Person
对象,而是ArrayList
对象。
与 writeReplace()
方法相对的还有一个叫做 readResolve()
的方法,有兴趣的可以去了解。
即实现 Externalizable
接口。这里不行写了,孩子太累了。。。
根据前面的介绍可知,反序列化的Java对象时必须提供该对象的class文件,现在的问题是,随着项目的升级,class文件会随之升级,Java如何保证两个class文件的兼容性?
Java的序列化机制允许为序列化类提供一个 private static final
的 serialVersionUID
值,该变量用于标识Java类的序列化版本,也就是说,当类升级以后,这个值不变,序列化机制会把他们当成同一个序列化版本。
如下:
1 | @Data |
这样的话,即使在某个对象被序列化之后,他所对应的类被修改了,该对象也依然可以被正确的反序列化。
前面介绍的BufferedReader
有一个特征:在读取输入流的数据时,如果没有读取到有效的数据,程序就会在此阻塞该线程的执行(使用 InputStream
的read()
方法从流中读取数据,如果没有数据的话,也会造成阻塞)。说人话就是前面介绍的输入输出流都是阻塞式的输入输出。除此之外,传统的输入输出都是以字节为单位来处理的,效率不高。
从JDK1.4开始,Java提供了一系列改进输入输出处理的新功能,这些功能统称为新IO(New IO,简称NIO)。
新IO将文件或文件的一段区域映射到内存中,这样就可以像访问内存一样来访问文件了(模拟了操作系统上虚拟内存的概念)
Java中与新IO相关的包:
java.nio
包:主要包含与各种Buffer相关的类java.nio.channels
包:主要包含与Channel和Selector相关的类java.nio.charset
包:主要包含与字符集相关的类java.channels.spi
包:主要包含与Channel相关的服务编程者接口java.nio.charset.spi
包:包含与字符集相关的服务提供者编程接口Channel(通道)和Buffer(缓冲)是新IO中两个核心对象:
map()
方法,通过该方法可以将“一块数据”映射到内存中;如果说传统的IO是面向流的处理,那么新IO就是面向块的处理除了Channel和Buffer,新IO也提供了用于将Unicode字符串映射成字节序列以及映射操作的Charset类,也提供了用于支持非阻塞输入输出的Selector类
1 | public class BufferTest { |
IPython
是一个与python交互的科学计算库(主要包括Numpy、pandas、Matplotlib等)紧密联系的交互式开发环境。
IPython
是一个python
的交互式shell
,比默认的python shell
好用得多,支持变量自动补全,自动缩进,支持bash shell
命令,内置了许多很有用的功能和函数。学习ipython
将会让我们以一种更高的效率来使用python
。同时它也是利用Python进行科学计算和交互可视化的一个最佳的平台。
1 | pip install --upgrade pip |
1 | pip install numpy |
1 | pip install pandas |
1 | pip install matplotlib |
1 | pip install ipython |
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。请你将两个数相加,并以相同形式返回一个表示和的链表。你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例 1:
1 | 输入:l1 = [2,4,3], l2 = [5,6,4] |
示例 2:
1 | 输入:l1 = [0], l2 = [0] |
示例 3:
1 | 输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9] |
提示:
1 | # Definition for singly-linked list. |
这边我之前犯了一个错误(代码如下),head和ll一开始引用同一个对象,当ll被赋为指向对象的next时,而指向对象的next为None,此时若再给ll赋新的对象,原先ll指向的对象的next并不会指向ll指向的新的对象,这两个对象没有任何联系,感觉这个可以用内存来解释。
1 | class ListNode(object): |
看到了一个用递归解题的大佬:
1 | class Solution: |
自己尝试用递归写:
1 | class Solution(object): |
n.模仿传递行为,文化基因,表情包
adj.舒服的
n.厌恶,反感
n.了解,见识;adj.有见识的;v.懂得,领悟
adj.书呆子气的,学究似的
v.轻声地笑;n.吃吃的笑,(母鸡的)咯咯声音
adv.完全的,绝对的
adj.着迷的,无法摆脱的,受困的
adj.令人捧腹的
吹捧;(在精神或健康方面)垮掉;捧腹大笑;撞坏
巧妙配对的单词和图像
珠穆朗玛峰
n.侵权,侵犯,违反
adj.华丽的,灿烂的
n.话题标签
n.服装; v.给…提供服装
n.匿名,不知姓名
someone or something that is beautiful,delicate or of the highest quality
)adj.优美的,精致的,赏心悦目的; n.过分讲究穿戴的人
接收,接管; 把…从某地带到另一地; 采用,承袭
兴风作浪,引起混乱
嘻哈套装
机器学习、深度学习的基础除了编程语言之外, 还有一个就是应用数学。一般包括线性代数
、概率论与信息论
、概率图
、数值计算与最优化
等。
一个标量是一个单独的数, 一般用小写的变量名称表示, 如a、z等
向量就是一列数或者一个一维数组, 我们可以把向量看作空间里的点, 如下: a可以看作一个一维数组
1 | import numpy as np |
就是一个二维数组, 具体操作见上一篇笔记
1 | import numpy as np |
矩阵还可以用嵌套向量生成, 和向量一样。
张量是向量和矩阵的推广, 标量–>零阶张量, 矩阵–>二阶张量, 以此类推。如一张图片就是一个三阶张量, 三个维度分别代表图片的高度、宽度和色彩数据。
1 | import numpy as np |
转置就是以主对角线(左上到右下)为轴进行镜像操作, 通俗来说就是行列互换, 如下所示:
1 | import numpy as np |
𝐴⁻¹𝐴=𝐼𝘯 (其中𝐼𝘯为单位矩阵)
只有对角线上的元素为非零元素, 其余全为零
𝐴=𝐴ᵀ
任意给定的向量𝘷, 若其𝙇²范数为, 即||𝘷||₂=1
, 则𝘷为单位向量
𝐴𝐴ᵀ=𝐴ᵀ𝐴=𝐼 (单位向量)
由多个同维度的的列向量构成的集合称为向量组
我们通过范数(Norm)来衡量向量的大小, 定义如下:
如何使用上代码:
1 | import numpy as np |
特征分解是使用最广的矩阵分解之一,将矩阵分解为一组特征向量和特征值。下面来看看他们的概念,设A是一个n阶方阵,如果存在实数$\lambda$和n维的非零向量x,满足:
$Ax=\lambda x$
那么$\lambda$称为方阵A的特征值,向量x为矩阵A对应特征值$\lambda$的特征向量
假设矩阵A有n个线性无关的特征向量{v¹, v², v³, ···, vⁿ},他们对应的特征值为{$\lambda$₁, $\lambda$₂, $\lambda$₃, ···, $\lambda$𝓃},把这n个线性无关的特征向量构成一个新方阵,每一列就是一个特征向量
$V=[v¹, v², v³, ···, vⁿ]$
用特征值构成一个n阶对角矩阵,对角线的元素都是特征值
$diag(\lambda)=[v¹, v², v³, ···, vⁿ]ᵀ$
那么,A的特征分解可表示为:
$A=Vdiag(\lambda)V⁻¹$
注意:并非所有的方阵都能进行特征值分解,一个方阵能进行特征值分解的充要条件是它含有n个线性无关的特征向量
下面我们来展示下求方阵的特征向量与特征值:
1 | import numpy as np |
迹运算返回的是矩阵对角元素的的和:
$Tr(A)=\sum_{i}A_{i,i}$
迹运算在某些场合非常有用,若不使用求和符号,某些矩阵运算很难描述。例如,迹运算提供了一种描述矩阵Frobenius范数的方式:
$||A||_{F}=\sqrt{Tr(AAᵀ)}$
利用NumPy对矩阵求迹同样方便,上代码
1 | import numpy as np |
IDEA一些简单的快捷键与简写,mac与Windows不一样
Ctrl + F | 在当前文件进行文本查找 |
---|---|
按住 Ctrl 键 | 在打开的文件标题上,弹出该文件路径 |
Ctrl + P | 方法参数提示显示 |
ALT + 左右 | 换小窗口 |
Alt + Enter | 修复错误 |
Shift + F10 | 快速运行项目 |
Ctrl + Alt + V | 快速引进变量 |
Ctrl + / | 注释光标所在行代码 |
/** | 注释 |
sout | |
psvm |