mathacker

no math, little hacker


  • Home

  • Categories

  • About

  • Archives

  • Tags

睡前故事一则

Posted on 2019-09-02 | In 故事

从前,有一个村妇,独自抚养着两个孩子——姐姐和弟弟。

有一天,村妇领着弟弟回娘家,让姐姐在家看门儿,临走前嘱咐说,不要给其他人开门。

半路上到了一个桥头,娘俩坐下来歇息。这时,走过来一个妖精。妖精说:“大姐,我给你看看头上有没有虱子吧”,村妇同意了。妖精开始边看虱子,边与村妇闲谈,然后,就一指甲一指甲把她吃掉了。

天黑的时候,妖精找到了村妇的家门前,敲了三下门。姐姐便问:“你是谁?不是我娘的话,我可不开门。” 妖精回答说:“我是你娘啊。”姐姐说:“你声音这么粗,不是我娘。” 妖精说:”路远口渴,声音变沙哑了。“姐姐说:”你伸过脚来我看看。“ 妖精便从门下的缝隙伸过脚去。姐姐说:”你脚这么大,不是我娘。”妖精说:“脚大是走路拍的。” 姐姐说:”你再伸过手来我看看。“ 妖精便从门缝中伸过手去。姐姐说:”你手这么大,不是我娘。”妖精说:“手大是走路甩的。”于是,姐姐开了门。

晚上,“两人”通腿睡下。半夜里,姐姐醒来,听到床那头有吃东西的声音,便说:”娘,你在吃什么?“ 妖精说:”我在吃萝卜。“ 姐姐说:”我也想吃。“ 妖精就扔了一块儿过来,姐姐一看,吓了一跳,竟然是弟弟的手指,就明白妖精做了什么了。

第二天晚上,隔壁家灯火通明,很是热闹。姐姐说:”娘,快来看啊,大爷家的哥哥在结婚哩,很热闹。“妖精说:“墙那么高,看不见啊”。姐姐说:“我在树上栓了一把椅子,把你拉上去。”姐姐没说的是,她还偷偷把一个烧得很烫的鏊子放在了椅子上。妖精走出屋来,一坐上椅子,姐姐就迅速把椅子拉了上去,妖精就这样烫死了。

nlp-in-action-ch01

Posted on 2019-08-18 | In NLP

NLP实战

Chatbot Recurrent Pipeline

  1. Parse: tokenizer, NER, extract info., reduce dim
  2. Analyze: spelling, grammar, sentiment, humanness, CNN, GAN
  3. Generate: search, templates, FSM, RNN…
  4. Execute: generate & classify…

序

2013年之后,NLP和聊天机器人的应用变得日益广泛,如愈来愈智能的Google Search、智能手机的自动完成功能。Gmail的Smart Reply令作者印象深刻。

从经典的马尔科夫链(词频、ngrams、条件概率等),可以实现一些颇为有用的功能,如Peter Norvig的spelling corrector。

PS:Peter的文章2016年有更新,或许会有新的启发,文章主要涉及传统的基于统计的语言模型。

接下来是隐语义分析(Latent Semantic Analysis, LSA),大致是持续跟踪那些共现的词,从而可将这些词归为topic。LSA将句子或文档的意思压缩为一个向量。

gensim库实现了Word2vec词向量,可将

第一部分 善谈的机器

1-4章

Ch01 NLP概述

Ch02 构建词汇表(Tokenizer)

Ch03 关于词的数学(TF-IDF)

Ch04 词频蕴含的意义(Semantic Analysis)

第二部分 深度学习

5-10章

Ch05 初识神经网络(感知机与反向传播)

Ch06 以词向量推理(Word2Vec)

Ch07 卷积神经网络(CNN)

Ch08 循环神经网络(RNN)

Ch09 LSTM

Ch10 Seq-to-seq模型

第三部分 来到现实世界

11-13章

Ch11 信息提取(NER与问题回答)

Ch12 对话引擎

Ch13 Scaling up

spacy

Posted on 2019-08-15 | In NLP

架构

spaCy的核心数据结构是Doc和Vocab。Doc对象持有token序列及其标注(annotation)信息,Vocab对象则持有一个查找表(look-up table),从而可在文档间共享信息。集中管理字符串、词向量与词法属性,避免了反复copy数据。

文本标注也是类似,Doc持有数据,Span和Token只是它的视图。Doc由Tokenizer构建,之后通过pipeline原地修改(modified in place)。Language对象协调以上诸组件,它接受原始文本,将其送入pipeline,返回一个标注了的文档,同时也参与了模型训练和序列化过程。

容器对象

  • Doc:包含语言标注的容器
  • Span:表示Doc的一个切片
  • Token:单个token,如词、标点、空格等
  • Lexeme:词位,词汇表的一个entry,不带任何上下文信息,因此也没有POS。

Pipeline

  • Language
  • Tokenizer
  • Lemmatizer
  • Tagger
  • Matcher
  • PhraseMatcher
  • EntityRuler
  • …

其它类

  • Vocab
  • StringStore
  • Vectors
  • …

爱的艺术读书笔记

Posted on 2019-06-05 | In Love

弗洛姆是德裔美籍心理学家,第一个研究“爱”和“爱的能力”的学者,除了《爱的艺术》,还有另一著作《逃避自由》。


一、爱是一门艺术吗?

爱是艺术,如绘画、木工,这意味着它需要去学习,努力学习。但也有人认为,爱不是艺术,而是一种偶然产生的令人心荡神怡的感受。如果是后者,那么爱不可学习,也不需要学习。

为什么说爱不可学?

若有此想法,大概因为以下视角:

  • 我是否值得被人爱:要赢得人心与对异性有吸引力(名利、权力、举止、谈吐等)
  • 爱是否成功主要看对象是谁:象对了,爱也就对了)
  • 爱,主要看人的交换价值:爱变为寻找”合适的对象“,人被物化
  • 爱是一种偶然的激情:只看激情,那么会以巨大的希望开始,以巨大的失望结束

现实中这几点不能说没有道理,甚至可以说主导了爱的领地。它们的问题是,没有关注对方,而爱却是两个人的事情。

具有吸引力,不一定会爱,比如某些成功人士、某些绅士;对象当然很重要,但指望“换一个对象”就解决问题,显然也是不现实的;考虑交换价值(有人会说自己行情如何,会说在相亲市场上处于何种位置),也无可厚非,家庭、教育、收入等,无疑决定了一个人的很多方面,但不可避免的是,过于关注这一方面,感情会变成一种“权衡”,权衡关注的是“合适”,而不是爱。

以上种种,都不能让人获得好的爱。其结果是,人们往往把注意力放在爱之外的方面,似乎爱是一种可以自动获得的能力。一个人愿意花很多时间在工作和学习上,而在爱上就吝啬得多了。

实际上,爱同绘画、木工等类似,也是一门艺术,需要专门的学习。要掌握爱的艺术,需要:

  • 重视爱这门艺术
  • 理论
  • 实践

二、为什么需要爱?

人生而孤独,故人的一大需要是摆脱孤独,摆脱被隔绝的状态。途径看起来有很多,总结下来不外乎:

  • 纵欲:性、毒品、酒;集体纵欲(如狂欢、暴力等),因属于集体从而无须有愧疚感;
  • 同一化:血缘之群体(家庭/家族);想象的共同体(民族/国家);与他人的一致性(主流价值观/不被孤立);
  • 创造性劳动:沉浸于艺术、木工等,进入心流;

各自问题:

  • 纵欲:短暂的,需不断重复
  • 同一:假的统一
  • 创造性劳动:不是人与人的结合

那要摆脱的最终答案是?

爱:) (实际上,爱是不能帮助人完全摆脱孤独感,甚至什么都不可以,但爱或许是最接近答案的一种)

要获得满意的爱,需要去了解爱是什么。

三、成熟的爱情是什么样的?

成熟爱情:保留自己的完整性、独立性,与他人合二为一。

爱情冲破两个人之间的高墙,客服孤独与隔绝感,同时保持自我的完整性。

四、爱的要素有哪些?

爱是一种积极的活动

所谓积极,是指内心生长的东西,而非被俘虏的情绪或外力驱使。它表现为”给“而非”得“。

“给”不是放弃、牺牲和交换,它表现或者激发了一个人的生命力,他分享欢乐、兴趣、知识等,结果是提高了彼此的生命感。

爱上一个人的感觉是美好的,远好于被人爱。

关心

真正去关心,不是”说“,不止是意愿。

责任心

不是”义务“,而是有能力且愿意负责。

尊重

正视对方,认识其独有个性,使他人成为他自己,而不是服务于我。

了解/认识

尊重的前提,否则关心或责任心是盲目的。

关心、责任心,一般人都会认同是爱的要素,但更重要的却是尊重与了解。

五、爱自己

爱一个人是一种能力,自己也是人,故爱自己也是一种能力。可以说,不会爱自己的人,不可能会爱其他人。

在爱自己、爱他人的过程中,我们不断了解”人“,这是爱的一个伟大之处。

Spark SQL

Posted on 2019-05-31 | In Apache Spark

RDD是无结构的,Spark 1.6引入了Structured API,后者是多数场景下更为适用。

Spark SQL基于Spark Core,包含两部分:

  • DataFrame & Dataset
  • Catalyst optimizer

结构化数据结构具有schema定义。

Creating DataFrames

RDDs and in Spark

Posted on 2019-05-31 | In Apache Spark

Rich Set of Operations

RDD提供了丰富的数据处理操作API,如transformation、filtering、grouping、joining、aggregation、sorting和counting。

PS:这些操作均是粗粒度的(coarse-grained),即同一操作被应用于多行,而非特定的一行。

RDD表示对数据的抽象,包含五部分信息:

  • partition集合,亦为整个数据集的chunk;
  • 对父级RDD的依赖关系
  • 对所有row进行计算的函数
  • partition scheme的元数据
  • 集群中数据的位置信息

Spark使用前三种信息以实现:确定RDD执行的顺序;失败恢复。

RDD Operations

RDD操作是粗粒度的,每一row表示为一个Java对象。Spark不关心row的结构,RDD的使用者负责如何处理每一行。更高层次的抽象如Spark SQL则在此基础上提供了其它计算。

RDD操作可分为两类:

  • Transformation(lazy):一个新的RDD
  • Action(eager):返回结果或将结果写入磁盘

Creating RDDs

1
2
3
4
val strs = Array("Spark", "RDDs")
val strRDD = spark.sparkContext.parallelize(strs)

val fileRDD = spark.sparkContext.textFile("/dev/spark-2.4.3-bin-hadoop2.7/README.md")

Transformation

Python中的协程

Posted on 2019-05-12 | In Programming

本文主要整理自《Fluent Python》的第16章。

David Beazley(又)尝言,协程是py文档中最语焉不详、模糊的,看起来是一个毫无用处的特性。当然,事实并非如此,他写过关于协程与并发的系列文章:A Curious Course on Coroutines and Concurrency。

yield一次在英语中有两个主要含义:产生和让路。在生成器中,这两个含义都适用:每次产生一个值,生成器都会挂起,“让路”给调用者。

协程的语法看起来像是生成器,但协程一般出现在表达式的右边(如datum = yield),它也不一定需要产生一个值。调用者使用.send()时,协程接受到一个值。

甚至可以完全没有数据从yield进出,所以不妨把yield看作一个流程控制装置,可用于实现协作式多任务处理:每个协程交出控制给central scheduler,随后其它协程可被激活。

协程的基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from inspect import getgeneratorstate


def simple_coro(a):
print('-> Started: a =', a)
b = yield a
print('-> Received: b =', b)
c = yield a + b
print('-> Received: c =', c)


coro = simple_coro(14)
print(getgeneratorstate(coro))
print(next(coro))
print(getgeneratorstate(coro))
print(coro.send(28))
print(coro.send(99))

从调用者角度看,它获取数据的方式与生成器类似,但是它同时多了两次send操作,send比next多了一个方向的数据流转,但对于yield,它依然会挂起当前例程(此处为协程),将执行交给调用者。

协程示例:持续计算均值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def averager():
total, count = 0, 0
average = None
while True:
term = yield average
total += term
count += 1
average = total / count


co = averager()
print(next(co))
print(co.send(10))
print(co.send(30))
print(co.send(5))

实现这一功能不是非得用协程,也可以用类或闭包,但在协程里,total和count都是简单的局部变量。

在上面两个例子中可以看到,使用协程都需要最开始调用一次next,这次操作一般称为“启动”(prime)。每个协程都需要启动,而协程也是函数,所以装饰器就派上用场了。

启动协程的装饰器

1
2
3
4
5
6
7
8
9
10
from functools import wraps


def coroutine(func):
@wraps(func)
def primer(*args, **kwargs):
gen = func(*args, **kwargs)
next(gen)
return gen
return primer

协程的终止与异常处理

.throw()与.close()。

协程的返回值

协程是生成器函数,因此可以有返回值,此时协程必须是正常终止的,比如whilebreak之后。

Python中的可迭代类型

Posted on 2019-05-10 | In Programming

本文主要整理自《Fluent Python》的第14章。

迭代(iteration)在数据处理中不可或缺的。当数据在内存中放不下时,我们需要偷一下懒(lazily),每次按需取一个数据项,这就是所谓的迭代器(iterator)模式。

Python 2.2(2001)添加了yield关键字,用以构造生成器(generator),生成器可达成迭代器的效果。而且,在Python社区中,生成器与迭代器同义。

Python中的每个集合(collection)都是可迭代的(iterable)。迭代器在内部用于:

  • for 循环
  • 集合类型的构造与扩展
  • 列表等类型的推导
  • tuple unpacking
  • *args的unpacking

本章涵盖以下主题:

  • iter函数
  • 如何实现经典的迭代器模式
  • 生成器工作机制
  • 经典的迭代器可用生成器替代
  • yield from语句
  • 生成器与协程(coroutine)看起来相似,本质上却非常不同

序列类型1:词序列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import re
import reprlib

RE_WORD = re.compile('r\w+')


class Sentence:
def __init__(self, sentence):
self.sentence = sentence
self.words = RE_WORD.findall(sentence)

def __getitem__(self, item):
return self.words[item]

def __len__(self):
return len(self.words)

def __repr__(self):
return f'Sentence({reprlib.repr(self.sentence)})'


if __name__ == '__main__':
sent = Sentence('"The time has come," the Walrus said,')
print(sent)

for word in sent:
print(word)

print(list(sent))
print(sent[0])

为何序列是可迭代的?

当解释器对一个对象x进行迭代时,它会自动调用iter(x),该内置函数会:

  • 检查对象是否实现了__iter__,有则调用之,并获取到一个迭代器;
  • 否则检查__getitem__,有则调用之,并创建一个迭代器;
  • 否则抛出TypeError

因为序列都实现了__getitem__,因此它们同时也是可迭代的,而标准库中的序列类型也会同时实现__iter__,我们实现序列类型时也需要如此。

这一处理方式导致了一个有趣的事实:一个iterable的对象不一定满足isinstance(o, abc.Iterable)。判断对象是否可迭代的准确方式是,对其迭代并捕获异常。

可迭代类型与迭代器类型

可迭代与迭代器的区别是,Python从iterable获取iterator。

下面的例子演示iterator类型的用法,不使用for循环:

1
2
3
4
5
6
7
8
s = 'abc'
it = iter(s)
while True:
try:
print(next(it))
except StopIteration:
del it
break

StopIteration表明迭代器已经迭代结束,在使用for循环时,该异常在其内部被处理掉了。

Iterator接口有两个方法:__next__、__iter__。

序列类型2:生成器函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Sentence:
def __init__(self, sentence):
self.sentence = sentence
self.words = RE_WORD.findall(sentence)

def __iter__(self):
for word in self.words:
yield word

def __len__(self):
return len(self.words)

def __repr__(self):
return f'Sentence({reprlib.repr(self.sentence)})'

这个版本的实现里,使用__iter__代替了__getitem__,因此更“地道”的可迭代实现。

分析

任何含有yield关键字的函数都是生成器函数(generator function),生成器函数的返回值是生成器对象。

序列类型3:更懒一点

在前两个版本的实现中,__init__会立即计算出所有的words,不管后面会不会用到,为了性能与占用内存计,我们希望类型能“更懒一点”。

使用Python 3时,每当你考虑“有否更懒的方式”,答案一般是肯定的。这里可以使用re.finditer():

1
2
3
4
5
6
7
8
9
10
class Sentence:
def __init__(self, sentence):
self.sentence = sentence

def __iter__(self):
for match in RE_WORD.finditer(self.sentence):
yield match.group()

def __repr__(self):
return f'Sentence({reprlib.repr(self.sentence)})'

修改之后,原来的self.words不再需要。不过,这还不是最短的实现。

序列类型4:生成器表达式

生成器表达式可以理解为惰性版的列表推导:如果列表推导是一个列表工厂,那么生成器表达式就是一个生成器工厂。

1
2
3
4
5
6
7
8
9
class Sentence:
def __init__(self, sentence):
self.sentence = sentence

def __iter__(self):
return (match.group() for match in RE_WORD.finditer(self.sentence))

def __repr__(self):
return f'Sentence({reprlib.repr(self.sentence)})'

生成器表达式只是语法糖,它们总是可以被替换为生成器函数,只是有时更为方便。

定义自己的range生成器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class ArithmeticProgression:

def __init__(self, begin=0, step=1, end=None):
self.begin = begin
self.step = step
self.end = end

def __iter__(self):
result = type(self.begin+self.step)(self.begin)
forever = self.end is None
index = 0
while forever or result < self.end:
yield result

index += 1
result = self.begin + self.step * index

这里的__iter__函数只是返回一个生成器,所以这个类实际上可以简化为生成器函数。

标准库中的生成器函数

这类函数定义在itertools和functools中,分为以下几类:

Filtering

  • compress:通过一个iterable对另一个过滤;
  • dropwhile
  • filter
  • filterfalse
  • islice:对任一iterable实施slice操作
  • takewhile:

Mapping

  • accumulate
  • enumerate
  • map
  • starmap

Merging Generators

  • chain
  • chain.from_iterable
  • product
  • zip
  • zip_longest

Expanding Generators

  • combinations
  • combinations_with_replacement
  • count
  • cycle
  • permutations
  • repeat

Rearranging Generators

  • groupby
  • reversed
  • tee

yield from

PS:py3.3引入的新语法。

生成器作为协程

py2.5引入了协程,协程向生成器对象添加了新的方法——主要是.send()。这一“enhancement”实际上改变了生成器的本质:如此一来,它们变成了协程。David Beazley尝言:

  • 生成器产生迭代器(用于迭代)
  • 协程是数据的消费者
  • 不要将两个概念混在一起使用
  • 协程与“迭代”无关

线性代数及其应用-线性代数中的线性方程组

Posted on 2017-10-24

原书链接:线性代数及其应用

0.1 前言

完成微积分的学生学习起来更易接受。

本身特点

  • 提前介绍主要概念
  • 矩阵乘法的现代观点:定义和证明中使用矩阵的“列”,而非“元素”,核心课题是将矩阵与向量之乘积$Ax$视为关于$A$的列的一个线性组合。这种现代方法简化了很多论述,并将向量空间和线性系统的研究联系在了一起。
  • 线性变换:贯穿整本书,增强了本书的几何趣味。
  • 特征值和动力系统:特征值来源并应用于离散动力系统和连续动力系统。
  • 正交性和最小二乘法:与普通入门教材相比,本书对这些主题的讨论更为全面。

0.2 给学生的注释

独立完成尽可能多的习题,过早查看答案,会误以为已经理解了尚未理解的概念。

线性代数是一种语言,用学习外语的方法每天学习这种语言。

数值计算的注解

关注一下这部分内容,因为现实中的应用通常会涉及一定误差下的计算,这部分可帮助你理解计算中潜在的困难。

Study Guide

善用之。

第一章 线性代数中的线性方程组

1949年夏末,哈佛大学教授列昂惕夫(Leontief)使用当时最大的计算机之一Mark II计算包含500个未知数的500个方程的方程组。由于运算量“过大”,他只好将问题简化为包含42个未知数的42个方程的方程组。他后来获得了诺贝尔经济学奖,他在哈佛的工作标志着应用计算机分析大规模数学模型的开始。

线性代数在科学的各个领域有极为广泛的应用。

线性方程组是线性代数的核心,本章以它来引入线性代数的许多重要概念。先介绍求解线性方程组的一个系统方法;再说明线性方程组等价于一个向量方程与矩阵方程,其后引出线性组合、线性表示与线性变换等概念。

1.1 线性方程组

本章先是讨论求解线性方程组的一个系统方法。早在初中数学里,我们就学过了线性方程组的求解方法,当时实际上已经提到了解法的一般过程,核心部分是消元,因为只有消元才能将方程转化为可直接求解的一元方程。本章讨论的系统方法也是循着这一思路。

包含未知数$x_1, x_2, \cdots, x_n$的一个线性方程是形如

$$a_1x_1 + a_2x_2 + \cdots + a_nx_n = b$$

的方程,其中$b$与诸系数是实数或复数,通常为已知数。

而线性方程组是由一个或几个包含相同变量$x_1, x_2, \cdots, x_n$的线性方程组成的。

方程组的一个解是一组数$(s_1, s_2, \cdots, s_n)$,解满足方程组的每一个方程。方程组所有可能的解的集合称为其解集。两个方程组称为等价的,若它们有相同的解集。

最简单的线性方程是二元一次方程,在几何上它对应于一条直线,它的解与直线上的点一一对应。而两个二元一次方程构成方程组的解集,即对应于两条直线的交点。两条直线可能会相交、平行或重合,这意味着该类方程组的解集也有三种情形:

  1. 唯一解
  2. 无穷多解
  3. 无解

我们说一个线性方程组是相容的,若它有一个或无穷多个解(即有解);否则称它为不相容的(即无解)。

1.1.1 矩阵记号

给定一个线性方程组,可以想见,该方程组解集的情况取决于系数和等式右端的常数,与未知数的具体记号无关,所以可以用一个矩阵(矩形阵列)来表示方程组,如

$$\begin{split}
x_1 - 2x_2 + x_3 = 0
\
2x_2 - 8x_3 = 8
\
-4x_1 + 5x_2 + 9x_3 = -9
\end{split}$$

矩阵

$$\begin{bmatrix}
1 & -2 & 1 \[0.3em]
0 & 2 & -8 \[0.3em]
-4 & 5 & 9
\end{bmatrix}$$

称为方程组的系数矩阵,而加上方程组右端常数列的

$$\begin{bmatrix}
1 & -2 & 1 & 0 \[0.3em]
0 & 2 & -8 & 8 \[0.3em]
-4 & 5 & 9 & 9
\end{bmatrix}$$

称为其增广矩阵。

矩阵的定义引出其维数的概念,表示其行列数。上述增广矩阵的维数是3行4列,一般矩阵称$m \times n$矩阵。

1.1.2 线性方程组的解法

基本思路是把方程组用一个更容易的等价方程组代替,类似于我们熟悉的消元法。

化简方程组有三种基本变换(即行初等变换):

  • 倍加
  • 对换
  • 倍乘(一行的所以元素乘以同一个非零数)

容易证明,一个方程组的增广矩阵经过若干次行初等变换后,新方程组与原方程组解集相同。而且,这些行变换是可逆的。

1.1.3 存在与唯一性问题

前面提及,线性方程组的解集有三种可能,可归为如下两个基本问题:

  1. 方程组是否相容,即它是否有解?
  2. 若它有解,解是否唯一?

通过行变换法,我们可以借助化简了的增广矩阵判断出方程组是否有解,进一步得出其解是否唯一。

1.1.4 解方程组与数值计算

计算机中的浮点数表示难免出现舍入误差,这种不精确性有时需要引起注意。

1.2 行化简与阶梯型矩阵

将1.1中的方法精确化后,可以得到行化简算法,可以解任意线性方程组,而且容易编程实现。这样就可以解决1.1中提出的存在与唯一性问题。该算法适用于任意矩阵。

矩阵中的非零行/列指矩阵中至少包含一个非零元素的行/列,非零行的先导元素指该行中最左边的非零元素。由此引出两类矩阵:

定义:一个矩阵称为阶梯形(或行阶梯形),若它有以下三个性质:

  1. 每一非零行在零行之上;
  2. 每一行的先导元素所在的列位于前一行先导元素的右面;
  3. 某一先导元素所在列下方元素都是零。

若一个阶梯形矩阵还满足以下性质,则称它为简化阶梯形:

  1. 每一非零行的先导元素是1;
  2. 每一先导元素1是该元素所在列的唯一非零元素。

若一个矩阵具有阶梯形(简化阶梯形),它就称为阶梯形(简化阶梯形)矩阵。一个矩阵可以行化简为阶梯形矩阵,不同的方法可能得到不同的阶梯形,但一个矩阵只能化为唯一的简化阶梯形矩阵。

定理1:每个矩阵行等价于唯一的简化阶梯形矩阵。

1.2.1 主元位置

矩阵化为阶梯形后,进一步化为简化阶梯形时,先导元素的位置并不改变,而简化阶梯形是唯一的,故一个矩阵的所有阶梯形的先导元素在相同的位置上。这些先导元素对应于简化阶梯形的先导1。

定义:矩阵中的主元位置是对应于其阶梯形中先导元素的位置,含有主元位置的列称为主元列。

将矩阵化为阶梯形就可以确定出主元位置,该过程可手工计算完成,由此可抽象出一个通用的行化简算法。

1.2.2 行化简算法

该算法分为5步,1-4步化矩阵为阶梯形,自左至右,称为向前步骤,第5步化阶梯形为简化阶梯形,自右至左,称为向后步骤。

数值计算的注解:第2步选择主元时,一般选择一列中绝对值最大的元素作为主元,此方法称为部分主元法,可减少舍入误差。

1.2.3 线性方程组的解

行化简算法应用于方程组的增广矩阵时,可以得出线性方程组解集的一种显式方法。比如,一个方程组化简之后如下:

$$\begin{split}
x_1 - 5x_3 = 1
\
x_2 + x_3 = 4
\
0 = 0
\end{split}$$

其相应的增广矩阵也得到了化简,对应于主元列的变量$x_1$和$x_2$称为基本变量,$x_3$则称为自由变量。

若方程组是相容的,其解集可显式表示出来。如果有自由变量,则用其表示基本变量。由于件化阶梯形中,每个基本变量仅包含在一行(一个方程)中,这是容易表示的。上面的方程组解集可表示为:

$$\begin{cases}
x_1 = 1 + 5x_3 \
x_2 = 4 - x_3 \
x_3是自由变量
\end{cases}
$$

所谓自由变量是指它可以取任意的值。自由变量的值确定之后,基本变量的值也随之确定下来。这种解集表示称为通解,因为它给出了方程组所有解的显式表示。此种表示亦称为解集的参数表示,其中自由变量作为参数。

若方程组是相容的,且具有自由变量,那么其解集具有多种参数表示,一般约定为使用自由变量作为参数来表示。

1.2.4 回代

计算机程序在解线性方程组时,通常使用回代法求解,即在阶梯形基础上回代,而非求出简化阶梯形后再求解。一个浮算(flop)就是两个浮点数的一次运算,一般地行化简算法的向前步骤比向后步骤需要更多运算。使用Matlab的flops可以计算某次计算中所需要的浮算次数。

手工计算时求出简化阶梯形更不易出错。

1.2.5 存在与唯一性问题

虽然非简化阶梯形不能直接解出线性方程组,但已足以回答关于方程组的两个基本问题,也就是如下的定理。

定理2:存在与唯一性定理

线性方程组相容的充要条件是增广矩阵的最右列不是主元列。若方程组相容,当其没有自由变量,有唯一解;否则有无穷多解。

《数学分析八讲》笔记

Posted on 2017-10-05

数学分析八讲 原书链接,作者辛钦。

前言

非数学专业的工程师、经济学家等,一般会先行学习较为简单的微积分,到了某个时候发现需要更为牢固的数学基础。如果找一本《微积分学教程》来看,事实证明效果不佳。学习者要么无法安排足够的时间去学习,要么还没有足够好的数学基础,无法从研究中区分出哪些是原则的内容,哪些是较为微末的细节。

要满足这类学生的需求,所需其实有限。我的秘诀是:从一开始就拒绝充分详细地讲授哪怕只是阐述本课程牟一章的想法,而只限于讲授那些具有原则性的内容。我讲的更多地是关于目的和趋势、问题和方法、基本的分析概念之间的以及它们与应用之间的关系,而不是个别的定理与证明。但在有着主导作用和原则意义的概念或方法上,我则不吝时间,力求用各种手段,通过各种表述和直观形象等,尽可能明白而有效地把这些基本内容教给我的学生。有了这个基础,他们每一个人在需要更深入地研究数学分析的某一章节时,就能够独立地找到他所需的材料,然后进行研究,也就是说,可以自立地区分主要和次要、本质和非本质。

第一讲 连续统

为什么数学分析必须从研究连续统开始?

如果对于变量$x$的每一个值,变量$y$都有唯一确定的值与之对应,那么变量$y$称为变量$x$的函数。

借助于这句话,我们可以定义最重要的、最首要的数学分析概念——函数关系。在此概念中,已经奠定了借助数学工具来把握自然现象和技术过程的完整思想的萌芽。由于其重要性,我们需要给该定义完全的明确性,其中的每一个字都不应有引起一点怀疑的阴影。

变量$x$的每一个值,构成了函数的定义域($x$称为自变量,$y$称为因变量)。而”值“具体是什么?它应该是数,那么定义域应当是一个数集。这里先排除掉虚数(其中的分析涉及复变函数),假设自变量与因变量皆为实数。

函数的定义域既取决于该函数的性质,也取决于特定的问题。前者给出自然定义域,后者给出更为特殊的定义域。

数学分析中,最常见的$x$集合是区间,区间或是有界的,或是无界的(半直线或直线)。无论如何,对于数学分析中的函数而言,最根本的数集是实数集。这个集合在数学中称为连续统(或线性连续统)。因其根本,所有认真而科学地编写的数学分析教程中,连续统都是第一个研究对象。

为什么没有建立完整的实数理论是不能研究连续统的?

那么连续统是什么样的?存在什么样的实数?如何我们才能相信已经了解了所有实数?

在所有的数中,我们最先接触到有理数,它可以表示可公度线段的长度,不管是整数值还是分数值,它是相当直观的。但有的线段长度无法用有理数表示,最经典的就是$\sqrt{2}$。这样,我们需要承认非有理数的存在,或更直接的无理数,如果不承认,某些线段的长度就无法表示。

有了无理数,就是引入了新数,新数需要确定出它与旧数的关系,至少有二:它与一个有理数的大小关系;它与有理数的运算表示,并且运算结果会产生其它新数,如$1 + \sqrt{2}$。

$\sqrt{2}$之后,不可避免地要考虑所有形如$r^{1/n}$的数,其中$r$是任意正有理数,$n$是$\geq 2$的整数。

继续这个过程,我们称形如$P(x) = 0$的方程的所有实根为代数数,其中的$P(x)$为带整系数的任意多项式,并把所有代数数引入到我们的新数集。特别地,任何有理数$r = \frac{p}{q}$可作为方程$qx - p = 0$的根包含进代数数的集合中。

代数数是我们数集的一个扩展,我们可以给出法则使其可以排序,以及进行代数运算。看起来已经是一个相当不错的扩展了。但是在分析之中,仅限于代数数是不够的。

代数数与极限

数学分析的第一步就要对初等代数运算添加基本且重要的分析运算——极限过程。极限不止是概念上的,还有具体而现实的意义,而且还要支持代数运算和分析运算。

如果任何代数数序列的极限都是代数数,那么我们是可以说,代数数集合就是连续统(关键在于,它能满足于我们的需要)。我们取单位圆,并且作出其内接正多边形,无限增加其边数,那么这些周长都可以用代数数表示。这个代数数序列的极限为圆周长(即$2\pi$)。这个极限必须承认是存在的,否则就等于是否定了圆周率。

另一方面,则可以证明这个极限不是代数数。这也说明,数学分析中仅考虑代数数是不够的。事实上,$\pi$这样的数称为超越数。我们的数集需要包含代数数与超越数。另一个重要的超越数是$e$。

那么,对于超越数我们能了解什么?现在只知道某些特殊的极限值是超越数,如$\pi$和$e$。是否可以说,我们的连续统包括所有的代数数,加上”根据需要,再添加某些特别的超越数“呢?这种定义的问题是:

  • 该集合不是一个确定性的集合,随时有可能需要添加新数
  • 该定义不像有理数和代数数那样具有一致的定义,也不够优雅
  • 该定义无法保证,对于新引入的数,可以一致地满足代数运算与极限运算(如代数数那样),在某些情况下,还需要引入其它数,这说明连续统还没有包含所有的实数

现在可以看到,对于连续统,我们不能仅限于”按照需要“引入几个新数,而是要给出建立实数的一般性理论,该理论适用于所有的实数。

无理数的构造

存在几种不同的连续统理论,它们在处理各自问题时的思路是完全一样的。在论证时,不需要囿于某一特定的理论,可以组合或交替使用。

所有这些理论都把有理数作为最初的数据,然后用统一的构造原则得到所有实数的集合。各种理论都基于统一思想,即:在构造新数时,基本解析极限过程起首要、主导的作用,所遇到的种种方法都可以归结为它。例如,$\sqrt{2}$的值可视为一个经过适当选择而得的有理数序列的极限。

构造连续统的三种方法是:

  • 戴德金分割方法
  • 康托尔的基本列方法
  • 魏尔斯特拉斯从十进小数表示出发的方法

本书采用戴德金分割法,因其在各种教材中被广泛的采纳。

在引入无理数之前,我们再仔细地观察以$R$(一般用$R$表示实数)表示的有理数集。首先是它的稠密性,即任何两个有理数$r_1$和$r_2$之间总可以找到第三个有理数,最简单的例子是两者的平均数。作为推论,我们可以得出,在$r_1$和$r_2$之间始终存在有理数的无穷集合。

现在,考察定义$\sqrt{2}$时的情况,该数不在有理数中。那么,如果仅考虑正有理数的话,任意给定有理数$r$,要么$r^2 < 2$,要么$r^2 > 2$。据此,正有理数可分为两类:A类,其中的数$r_1$满足$r_1^2 < 2$,B类,其中的数$r_2$满足$r_2^2 < 2$,因$r_1, r_2$皆为正数,故有$r_1 < r_2$。这说明A类中的每个数都小于B类中的每个数。然后我们把零和所有负数归到A类,那么上述结论不变。这时我们得到有理数集的一个分割。

若将$R$分为两个非空的类(A,B),且A类中的每一个数都小于B类,就称之为分割。

我们可以用更简单的方法得到分割。如把所有小于等于5的数归为A类,大于5的归为B类。如果把有理数对应到数轴上的点,那么这种分割是非常直观的。

现在我们有两个分割的例子,即由$\sqrt{2}$和$5$构造的。它们只是有位置的差别,还是有本质的区别?对于我们构造实数这一目的来说,它们是很不一样的。原因是,第二个分割中,$5$将有理数分割为两类,所有其它的数,或大于或小于它,而它自身也属于有理数,这种数称为分割的界限;而第一个分割不存在这样的界限。

PS:界限,是指其本身是有理数,同时小于它的有理数属于一类,大于大的有理数属于另一类。是故$5$是界限,而$\sqrt{2}$所定义的分割没有界限(证明见P6)。

这样有理数集$R$的所有分割分为两种类型:有界限的和无界限的。此外,界限还有其它性质:

  • 一个分割不可能有两个界限
  • 若界限存在,则其要么是$A$类最大数,要么是$B$类最小数
  • 每一个有理数$r_0$都是两个不同分割的界限,其一的$A$类是$r \leq r_0$,其二的$A$类是$r < r_0$

由$\sqrt{2}$的例子可以看出,这样的数是存在的(单位正方形的对角线长度),而且如果不添加这样的数,那么数集就没有其连续性和致密性。因此,我们可考虑依据分割的界限来定义新数,即无理数。

对于有理数集$R$的每一个没有界限的分割,我们都定义一个新的无理数与之对应,并定义此无理数即分割的界限。根据这个统一的原则,我们就确定了整个无理数的集合。连同已知的有理数集,它们构成了所有实数的几何,即连续统。

连续统理论

上面由分割,可以构造新的无理数,或者说所有的无理数,但这一原则只是连续统理论的开始,还有大量其它工作要做:

  • 对连续统排序,确定两个实数的大小关系
  • 对实数定义运算,比如$1 + \sqrt{2}$的值是什么
  • 新运算具有有理数域中我们所熟知的全部性质,如加法的交换律
  • 确认我们定义的连续统确实已经适应了所有实际和直观表示之需要

以下将讨论实数的各个性质,须知有理数和无理数都对应到两个分割,有理数是分割的界限且为最大/小数,无理数则不是界限,其分类亦无最大/小数。

排序

利用上面提及的实数与分割关系可以证得(详见P8),两个实数各自决定的分割也决定了它们之间的大小关系。

运算

在P8-9,书中以实数加法运算为例说明了如何为连续统添加运算,以及这些运算仍然满足旧有的运算律。

连续统的连续性

至此所谈及的分割都是对于有理数集的分割,这些分割有的是不存在界限的,如$\sqrt{2}$,看起来就像是有理数之间夹杂着一些不属于有理数的数,那么以数轴的角度看,有理数集是不连续的。这种不连续性也是我们扩展有理数集的原因。

引入无理数并且定义了实数的排序后,也可以定义连续统的分割。如果每一个连续统的分割都有一个实数作为界限(证明见P10),那么我们可以说连续统本身是连续的,这样就弥补了有理数集的不足,而数学分析的讨论就可以继续下去了。

基本引理

以分割建立起来的连续统为我们带来了数学分析的逻辑基础。理论上来说,接下来的所有研究都可以直接回溯到分割的定义去解决问题,但实际上很多时候,构造分割是繁琐的过程。数学家们引入了几个辅助命题(引理),这些引理在很多情况下比分割更为方便,一旦证明了这些引理,就可以把它们和分割定义一起作为后续研究的工具。

关于单调序列的引理

引理1:任何单调有界序列都有极限。

第二讲 极限

12345
Anders Cui

Anders Cui

47 posts
13 categories
30 tags
© June 2017 - 2021 Anders Cui
Powered by Hexo
Theme - NexT.Mist