Girish Managoli 发布的文章

用朴素贝叶斯分类器解决现实世界里的机器学习问题。

 title=

朴素贝叶斯 Naïve Bayes 是一种分类技术,它是许多分类器建模算法的基础。基于朴素贝叶斯的分类器是简单、快速和易用的机器学习技术之一,而且在现实世界的应用中很有效。

朴素贝叶斯是从 贝叶斯定理 Bayes' theorem 发展来的。贝叶斯定理由 18 世纪的统计学家 托马斯·贝叶斯 提出,它根据与一个事件相关联的其他条件来计算该事件发生的概率。比如,帕金森氏病 患者通常嗓音会发生变化,因此嗓音变化就是与预测帕金森氏病相关联的症状。贝叶斯定理提供了计算目标事件发生概率的方法,而朴素贝叶斯是对该方法的推广和简化。

解决一个现实世界里的问题

这篇文章展示了朴素贝叶斯分类器解决现实世界问题(相对于完整的商业级应用)的能力。我会假设你对机器学习有基本的了解,所以文章里会跳过一些与机器学习预测不大相关的步骤,比如 数据打乱 date shuffling 数据切片 data splitting 。如果你是机器学习方面的新手或者需要一个进修课程,请查看 《An introduction to machine learning today》 和 《Getting started with open source machine learning》。

朴素贝叶斯分类器是 有监督的 supervised 、属于 生成模型 generative 的、非线性的、属于 参数模型 parametric 的和 基于概率的 probabilistic

在这篇文章里,我会演示如何用朴素贝叶斯预测帕金森氏病。需要用到的数据集来自 UCI 机器学习库。这个数据集包含许多语音信号的指标,用于计算患帕金森氏病的可能性;在这个例子里我们将使用这些指标中的前 8 个:

  • MDVP:Fo(Hz):平均声带基频
  • MDVP:Fhi(Hz):最高声带基频
  • MDVP:Flo(Hz):最低声带基频
  • MDVP:Jitter(%)MDVP:Jitter(Abs)MDVP:RAPMDVP:PPQJitter:DDP:5 个衡量声带基频变化的指标

这个例子里用到的数据集,可以在我的 GitHub 仓库 里找到。数据集已经事先做了打乱和切片。

用 Python 实现机器学习

接下来我会用 Python 来解决这个问题。我用的软件是:

  • Python 3.8.2
  • Pandas 1.1.1
  • scikit-learn 0.22.2.post1

Python 有多个朴素贝叶斯分类器的实现,都是开源的,包括:

  • NLTK Naïve Bayes:基于标准的朴素贝叶斯算法,用于文本分类
  • NLTK Positive Naïve Bayes:NLTK Naïve Bayes 的变体,用于对只标注了一部分的训练集进行二分类
  • Scikit-learn Gaussian Naïve Bayes:提供了部分拟合方法来支持数据流或很大的数据集(LCTT 译注:它们可能无法一次性导入内存,用部分拟合可以动态地增加数据)
  • Scikit-learn Multinomial Naïve Bayes:针对离散型特征、实例计数、频率等作了优化
  • Scikit-learn Bernoulli Naïve Bayes:用于各个特征都是二元变量/布尔特征的情况

在这个例子里我将使用 sklearn Gaussian Naive Bayes

我的 Python 实现在 naive_bayes_parkinsons.py 里,如下所示:

import pandas as pd

# x_rows 是我们所使用的 8 个特征的列名
x_rows=['MDVP:Fo(Hz)','MDVP:Fhi(Hz)','MDVP:Flo(Hz)',
        'MDVP:Jitter(%)','MDVP:Jitter(Abs)','MDVP:RAP','MDVP:PPQ','Jitter:DDP']
y_rows=['status'] # y_rows 是类别的列名,若患病,值为 1,若不患病,值为 0

# 训练

# 读取训练数据
train_data = pd.read_csv('parkinsons/Data_Parkinsons_TRAIN.csv')
train_x = train_data[x_rows]
train_y = train_data[y_rows]
print("train_x:\n", train_x)
print("train_y:\n", train_y)

# 导入 sklearn Gaussian Naive Bayes,然后进行对训练数据进行拟合
from sklearn.naive_bayes import GaussianNB

gnb = GaussianNB()
gnb.fit(train_x, train_y)

# 对训练数据进行预测
predict_train = gnb.predict(train_x)
print('Prediction on train data:', predict_train)

# 在训练数据上的准确率
from sklearn.metrics import accuracy_score
accuracy_train = accuracy_score(train_y, predict_train)
print('Accuray score on train data:', accuracy_train)

# 测试

# 读取测试数据
test_data = pd.read_csv('parkinsons/Data_Parkinsons_TEST.csv')
test_x = test_data[x_rows]
test_y = test_data[y_rows]

# 对测试数据进行预测
predict_test = gnb.predict(test_x)
print('Prediction on test data:', predict_test)

# 在测试数据上的准确率
accuracy_test = accuracy_score(test_y, predict_test)
print('Accuray score on test data:', accuracy_train)

运行这个 Python 脚本:

$ python naive_bayes_parkinsons.py

train_x:
      MDVP:Fo(Hz)  MDVP:Fhi(Hz) ...  MDVP:RAP  MDVP:PPQ  Jitter:DDP
0        152.125       161.469  ...   0.00191   0.00226     0.00574
1        120.080       139.710  ...   0.00180   0.00220     0.00540
2        122.400       148.650  ...   0.00465   0.00696     0.01394
3        237.323       243.709  ...   0.00173   0.00159     0.00519
..           ...           ...           ...  ...       ...       ...        
155      138.190       203.522  ...   0.00406   0.00398     0.01218

[156 rows x 8 columns]

train_y:
      status
0         1
1         1
2         1
3         0
..      ...
155       1

[156 rows x 1 columns]

Prediction on train data: [1 1 1 0 ... 1]
Accuracy score on train data: 0.6666666666666666

Prediction on test data: [1 1 1 1 ... 1
 1 1]
Accuracy score on test data: 0.6666666666666666

在训练集和测试集上的准确率都是 67%。它的性能还可以进一步优化。你想尝试一下吗?你可以在下面的评论区给出你的方法。

背后原理

朴素贝叶斯分类器从贝叶斯定理发展来的。贝叶斯定理用于计算条件概率,或者说贝叶斯定理用于计算当与一个事件相关联的其他事件发生时,该事件发生的概率。简而言之,它解决了这个问题:如果我们已经知道事件 x 发生在事件 y 之前的概率,那么当事件 x 再次发生时,事件 y 发生的概率是多少? 贝叶斯定理用一个先验的预测值来逐渐逼近一个最终的 后验概率。贝叶斯定理有一个基本假设,就是所有的参数重要性相同(LCTT 译注:即相互独立)。

贝叶斯计算主要包括以下步骤:

  1. 计算总的先验概率:
    P(患病)P(患病) 和 P(不患病)P(不患病)
  2. 计算 8 种指标各自是某个值时的后验概率 (value1,...,value8 分别是 MDVP:Fo(Hz),...,Jitter:DDP 的取值):
    P(value1,\ldots,value8\ |\ 患病)P(value1,…,value8 ∣ 患病)
    P(value1,\ldots,value8\ |\ 不患病)P(value1,…,value8 ∣ 不患病)
  3. 将第 1 步和第 2 步的结果相乘,最终得到患病和不患病的后验概率:
    P(患病\ |\ value1,\ldots,value8) \propto P(患病) \times P(value1,\ldots,value8\ |\ 患病)P(患病 ∣ value1,…,value8)∝P(患病)×P(value1,…,value8 ∣ 患病)
    P(不患病\ |\ value1,\ldots,value8) \propto P(不患病) \times P(value1,\ldots,value8\ |\ 不患病)P(不患病 ∣ value1,…,value8)∝P(不患病)×P(value1,…,value8 ∣ 不患病)

上面第 2 步的计算非常复杂,朴素贝叶斯将它作了简化:

  1. 计算总的先验概率:
    P(患病)P(患病) 和 P(不患病)P(不患病)
  2. 对 8 种指标里的每个指标,计算其取某个值时的后验概率:
    P(value1\ |\ 患病),\ldots,P(value8\ |\ 患病)P(value1 ∣ 患病),…,P(value8 ∣ 患病)
    P(value1\ |\ 不患病),\ldots,P(value8\ |\ 不患病)P(value1 ∣ 不患病),…,P(value8 ∣ 不患病)
  3. 将第 1 步和第 2 步的结果相乘,最终得到患病和不患病的后验概率:
    P(患病\ |\ value1,\ldots,value8) \propto P(患病) \times P(value1\ |\ 患病) \times \ldots \times P(value8\ |\ 患病)P(患病 ∣ value1,…,value8)∝P(患病)×P(value1 ∣ 患病)×…×P(value8 ∣ 患病)
    P(不患病\ |\ value1,\ldots,value8) \propto P(不患病) \times P(value1\ |\ 不患病) \times \ldots \times P(value8\ |\ 不患病)P(不患病 ∣ value1,…,value8)∝P(不患病)×P(value1 ∣ 不患病)×…×P(value8 ∣ 不患病)

这只是一个很初步的解释,还有很多其他因素需要考虑,比如数据类型的差异,稀疏数据,数据可能有缺失值等。

超参数

朴素贝叶斯作为一个简单直接的算法,不需要超参数。然而,有的版本的朴素贝叶斯实现可能提供一些高级特性(比如超参数)。比如,GaussianNB 就有 2 个超参数:

  • priors:先验概率,可以事先指定,这样就不必让算法从数据中计算才能得出。
  • var\_smoothing:考虑数据的分布情况,当数据不满足标准的高斯分布时,这个超参数会发挥作用。

损失函数

为了坚持简单的原则,朴素贝叶斯使用 0-1 损失函数。如果预测结果与期望的输出相匹配,损失值为 0,否则为 1。

优缺点

优点:朴素贝叶斯是最简单、最快速的算法之一。
优点:在数据量较少时,用朴素贝叶斯仍可作出可靠的预测。
缺点:朴素贝叶斯的预测只是估计值,并不准确。它胜在速度而不是准确度。
缺点:朴素贝叶斯有一个基本假设,就是所有特征相互独立,但现实情况并不总是如此。

从本质上说,朴素贝叶斯是贝叶斯定理的推广。它是最简单最快速的机器学习算法之一,用来进行简单和快速的训练和预测。朴素贝叶斯提供了足够好、比较准确的预测。朴素贝叶斯假设预测特征之间是相互独立的。已经有许多朴素贝叶斯的开源的实现,它们的特性甚至超过了贝叶斯算法的实现。


via: https://opensource.com/article/21/1/machine-learning-python

作者:Girish Managoli 选题:lujun9972 译者:tanloong 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

进一步学习自然语言处理的基本概念

 title=

之前的文章 里,我介绍了 自然语言处理 natural language processing (NLP)和宾夕法尼亚大学研发的 自然语言处理工具包 Natural Language Toolkit (NLTK)。我演示了用 Python 解析文本和定义 停顿词 stopword 的方法,并介绍了 语料库 corpus 的概念。语料库是由文本构成的数据集,通过提供现成的文本数据来辅助文本处理。在这篇文章里,我将继续用各种语料库对文本进行对比和分析。

这篇文章主要包括以下部分:

  • 词网 WordNet 同义词集 synset
  • 相似度比较 Similarity comparison
  • Tree 树库 treebank
  • 命名实体识别 Named entity recognition

词网和同义词集

词网 WordNet 是 NLTK 里的一个大型词汇数据库语料库。词网包含各单词的诸多 认知同义词 cognitive synonyms (认知同义词常被称作“ 同义词集 synset ”)。在词网里,名词、动词、形容词和副词,各自被组织成一个同义词的网络。

词网是一个很有用的文本分析工具。它有面向多种语言的版本(汉语、英语、日语、俄语和西班牙语等),也使用多种许可证(从开源许可证到商业许可证都有)。初代版本的词网由普林斯顿大学研发,面向英语,使用 类 MIT 许可证 MIT-like license

因为一个词可能有多个意义或多个词性,所以可能与多个同义词集相关联。每个同义词集通常提供下列属性:

属性定义例子
名称 Name 此同义词集的名称单词 code 有 5 个同义词集,名称分别是 code.n.01code.n.02code.n.03code.v.01code.v.02
词性 POS 此同义词集的词性单词 code 有 3 个名词词性的同义词集和 2 个动词词性的同义词集
定义 Definition 该词作对应词性时的定义动词 code 的一个定义是:(计算机科学)数据或计算机程序指令的 象征性排列 symbolic arrangement
例子 Example 使用该词的例子code 一词的例子:We should encode the message for security reasons
词元 Lemma 与该词相关联的其他同义词集(包括那些不一定严格地是该词的同义词,但可以大体看作同义词的);词元直接与其他词元相关联,而不是直接与 单词 word 相关联code.v.02 的词元是 code.v.02.enciphercode.v.02.ciphercode.v.02.cyphercode.v.02.encryptcode.v.02.inscribecode.v.02.write_in_code
反义词 Antonym 意思相反的词词元 encode.v.01.encode 的反义词是 decode.v.01.decode
上义词 Hypernym 该词所属的一个范畴更大的词code.v.01 的一个上义词是 tag.v.01
分项词 Meronym 属于该词组成部分的词computer 的一个分项词是 chip
总项词 Holonym 该词作为组成部分所属的词window 的一个总项词是 computer screen

同义词集还有一些其他属性,在 <你的 Python 安装路径>/Lib/site-packages 下的 nltk/corpus/reader/wordnet.py,你可以找到它们。

下面的代码或许可以帮助理解。

这个函数:

from nltk.corpus import wordnet

def synset_info(synset):
    print("Name", synset.name())
    print("POS:", synset.pos())
    print("Definition:", synset.definition())
    print("Examples:", synset.examples())
    print("Lemmas:", synset.lemmas())
    print("Antonyms:", [lemma.antonyms() for lemma in synset.lemmas() if len(lemma.antonyms()) > 0])
    print("Hypernyms:", synset.hypernyms())
    print("Instance Hypernyms:", synset.instance_hypernyms())
    print("Part Holonyms:", synset.part_holonyms())
    print("Part Meronyms:", synset.part_meronyms())
    print()


synsets = wordnet.synsets('code')
print(len(synsets), "synsets:")
for synset in synsets:
    synset_info(synset)

将会显示:

5 synsets:
Name code.n.01
POS: n
Definition: a set of rules or principles or laws (especially written ones)
Examples: []
Lemmas: [Lemma('code.n.01.code'), Lemma('code.n.01.codification')]
Antonyms: []
Hypernyms: [Synset('written_communication.n.01')]
Instance Hpernyms: []
Part Holonyms: []
Part Meronyms: []

...

Name code.n.03
POS: n
Definition: (computer science) the symbolic arrangement of data or instructions in a computer program or the set of such instructions
Examples: []
Lemmas: [Lemma('code.n.03.code'), Lemma('code.n.03.computer_code')]
Antonyms: []
Hypernyms: [Synset('coding_system.n.01')]
Instance Hpernyms: []
Part Holonyms: []
Part Meronyms: []

...

Name code.v.02
POS: v
Definition: convert ordinary language into code
Examples: ['We should encode the message for security reasons']
Lemmas: [Lemma('code.v.02.code'), Lemma('code.v.02.encipher'), Lemma('code.v.02.cipher'), Lemma('code.v.02.cypher'), Lemma('code.v.02.encrypt'), Lemma('code.v.02.inscribe'), Lemma('code.v.02.write_in_code')]
Antonyms: []
Hypernyms: [Synset('encode.v.01')]
Instance Hpernyms: []
Part Holonyms: []
Part Meronyms: []

同义词集 synset 词元 lemma 在词网里是按照树状结构组织起来的,下面的代码会给出直观的展现:

def hypernyms(synset):
    return synset.hypernyms()

synsets = wordnet.synsets('soccer')
for synset in synsets:
    print(synset.name() + " tree:")
    pprint(synset.tree(rel=hypernyms))
    print()
code.n.01 tree:
[Synset('code.n.01'),
 [Synset('written_communication.n.01'),
   ...

code.n.02 tree:
[Synset('code.n.02'),
 [Synset('coding_system.n.01'),
   ...

code.n.03 tree:
[Synset('code.n.03'),
   ...

code.v.01 tree:
[Synset('code.v.01'),
 [Synset('tag.v.01'),
   ...

code.v.02 tree:
[Synset('code.v.02'),
 [Synset('encode.v.01'),
   ...

词网并没有涵盖所有的单词和其信息(现今英语有约 17,0000 个单词,最新版的 词网 涵盖了约 15,5000 个),但它开了个好头。掌握了“词网”的各个概念后,如果你觉得它词汇少,不能满足你的需要,可以转而使用其他工具。或者,你也可以打造自己的“词网”!

自主尝试

使用 Python 库,下载维基百科的 “open source” 页面,并列出该页面所有单词的 同义词集 synset 词元 lemma

相似度比较

相似度比较的目的是识别出两篇文本的相似度,在搜索引擎、聊天机器人等方面有很多应用。

比如,相似度比较可以识别 footballsoccer 是否有相似性。

syn1 = wordnet.synsets('football')
syn2 = wordnet.synsets('soccer')

# 一个单词可能有多个 同义词集,需要把 word1 的每个同义词集和 word2 的每个同义词集分别比较
for s1 in syn1:
    for s2 in syn2:
        print("Path similarity of: ")
        print(s1, '(', s1.pos(), ')', '[', s1.definition(), ']')
        print(s2, '(', s2.pos(), ')', '[', s2.definition(), ']')
        print("   is", s1.path_similarity(s2))
        print()
Path similarity of:
Synset('football.n.01') ( n ) [ any of various games played with a ball (round or oval) in which two teams try to kick or carry or propel the ball into each other's goal ]
Synset('soccer.n.01') ( n ) [ a football game in which two teams of 11 players try to kick or head a ball into the opponents' goal ]
   is 0.5

Path similarity of:
Synset('football.n.02') ( n ) [ the inflated oblong ball used in playing American football ]
Synset('soccer.n.01') ( n ) [ a football game in which two teams of 11 players try to kick or head a ball into the opponents' goal ]
   is 0.05

两个词各个同义词集之间 路径相似度 path similarity 最大的是 0.5,表明它们关联性很大( 路径相似度 path similarity 指两个词的意义在 上下义关系的词汇分类结构 hypernym/hypnoym taxonomy 中的最短距离)。

那么 codebug 呢?这两个计算机领域的词的相似度是:

Path similarity of:
Synset('code.n.01') ( n ) [ a set of rules or principles or laws (especially written ones) ]
Synset('bug.n.02') ( n ) [ a fault or defect in a computer program, system, or machine ]
   is 0.1111111111111111
...
Path similarity of:
Synset('code.n.02') ( n ) [ a coding system used for transmitting messages requiring brevity or secrecy ]
Synset('bug.n.02') ( n ) [ a fault or defect in a computer program, system, or machine ]
   is 0.09090909090909091
...
Path similarity of:
Synset('code.n.03') ( n ) [ (computer science) the symbolic arrangement of data or instructions in a computer program or the set of such instructions ]
Synset('bug.n.02') ( n ) [ a fault or defect in a computer program, system, or machine ]
   is 0.09090909090909091

这些是这两个词各同义词集之间 路径相似度 path similarity 的最大值,这些值表明两个词是有关联性的。

NLTK 提供多种 相似度计分器 similarity scorers ,比如:

  • path\_similarity
  • lch\_similarity
  • wup\_similarity
  • res\_similarity
  • jcn\_similarity
  • lin\_similarity

要进一步了解这些 相似度计分器 similarity scorers ,请查看 WordNet Interface 的 Similarity 部分。

自主尝试

使用 Python 库,从维基百科的 Category: Lists of computer terms 生成一个术语列表,然后计算各术语之间的相似度。

树和树库

使用 NLTK,你可以把文本表示成树状结构以便进行分析。

这里有一个例子:

这是一份简短的文本,对其做预处理和词性标注:

import nltk

text = "I love open source"
# Tokenize to words
words = nltk.tokenize.word_tokenize(text)
# POS tag the words
words_tagged = nltk.pos_tag(words)

要把文本转换成树状结构,你必须定义一个 语法 grammar 。这个例子里用的是一个基于 Penn Treebank tags 的简单语法。

# A simple grammar to create tree
grammar = "NP: {&lt;JJ&gt;&lt;NN&gt;}"

然后用这个 语法 grammar 创建一颗 tree

# Create tree
parser = nltk.RegexpParser(grammar)
tree = parser.parse(words_tagged)
pprint(tree)

运行上面的代码,将得到:

Tree('S', [('I', 'PRP'), ('love', 'VBP'), Tree('NP', [('open', 'JJ'), ('source', 'NN')])])

你也可以图形化地显示结果。

tree.draw()

 title=

这个树状结构有助于准确解读文本的意思。比如,用它可以找到文本的 主语):

subject_tags = ["NN", "NNS", "NP", "NNP", "NNPS", "PRP", "PRP$"]
def subject(sentence_tree):
    for tagged_word in sentence_tree:
        # A crude logic for this case -  first word with these tags is considered subject
        if tagged_word[1] in subject_tags:
            return tagged_word[0]

print("Subject:", subject(tree))

结果显示主语是 I

Subject: I

这是一个比较基础的文本分析步骤,可以用到更广泛的应用场景中。 比如,在聊天机器人方面,如果用户告诉机器人:“给我妈妈 Jane 预订一张机票,1 月 1 号伦敦飞纽约的”,机器人可以用这种分析方法解读这个指令:

动作: 预订
动作的对象: 机票
乘客: Jane
出发地: 伦敦
目的地: 纽约
日期: (明年)1 月 1 号

树库 treebank 指由许多预先标注好的 tree 构成的语料库。现在已经有面向多种语言的树库,既有开源的,也有限定条件下才能免费使用的,以及商用的。其中使用最广泛的是面向英语的宾州树库。宾州树库取材于 华尔街日报 Wall Street Journal 。NLTK 也包含了宾州树库作为一个子语料库。下面是一些使用 树库 treebank 的方法:

words = nltk.corpus.treebank.words()
print(len(words), "words:")
print(words)

tagged_sents = nltk.corpus.treebank.tagged_sents()
print(len(tagged_sents), "sentences:")
print(tagged_sents)

100676 words:
['Pierre', 'Vinken', ',', '61', 'years', 'old', ',', ...]
3914 sentences:
[[('Pierre', 'NNP'), ('Vinken', 'NNP'), (',', ','), ('61', 'CD'), ('years', 'NNS'), ('old', 'JJ'), (',', ','), ('will', 'MD'), ('join', 'VB'), ('the', 'DT'), ('board', 'NN'), ('as', 'IN'), ('a', 'DT'), ('nonexecutive', 'JJ'), ('director', 'NN'), ...]

查看一个句子里的各个 标签 tags

sent0 = tagged_sents[0]
pprint(sent0)
[('Pierre', 'NNP'),
 ('Vinken', 'NNP'),
 (',', ','),
 ('61', 'CD'),
 ('years', 'NNS'),
...

定义一个 语法 grammar 来把这个句子转换成树状结构:

grammar = '''
    Subject: {<NNP><NNP>}
    SubjectInfo: {<CD><NNS><JJ>}
    Action: {<MD><VB>}
    Object: {<DT><NN>}
    Stopwords: {<IN><DT>}
    ObjectInfo: {<JJ><NN>}
    When: {<NNP><CD>}
'''
parser = nltk.RegexpParser(grammar)
tree = parser.parse(sent0)
print(tree)
(S
  (Subject Pierre/NNP Vinken/NNP)
  ,/,
  (SubjectInfo 61/CD years/NNS old/JJ)
  ,/,
  (Action will/MD join/VB)
  (Object the/DT board/NN)
  as/IN
  a/DT
  (ObjectInfo nonexecutive/JJ director/NN)
  (Subject Nov./NNP)
  29/CD
  ./.)

图形化地显示:

tree.draw()

 title=

trees 树库 treebanks 的概念是文本分析的一个强大的组成部分。

自主尝试

使用 Python 库,下载维基百科的 “open source” 页面,将得到的文本以图形化的树状结构展现出来。

命名实体识别

无论口语还是书面语都包含着重要数据。文本处理的主要目标之一,就是提取出关键数据。几乎所有应用场景所需要提取关键数据,比如航空公司的订票机器人或者问答机器人。 NLTK 为此提供了一个 命名实体识别 named entity recognition 的功能。

这里有一个代码示例:

sentence = 'Peterson first suggested the name "open source" at Palo Alto, California'

验证这个句子里的 人名 name 地名 place 有没有被识别出来。照例先预处理:

import nltk

words = nltk.word_tokenize(sentence)
pos_tagged = nltk.pos_tag(words)

运行 命名实体标注器 named-entity tagger

ne_tagged = nltk.ne_chunk(pos_tagged)
print("NE tagged text:")
print(ne_tagged)
print()
NE tagged text:
(S
  (PERSON Peterson/NNP)
  first/RB
  suggested/VBD
  the/DT
  name/NN
  ``/``
  open/JJ
  source/NN
  ''/''
  at/IN
  (FACILITY Palo/NNP Alto/NNP)
  ,/,
  (GPE California/NNP))

上面的结果里,命名实体被识别出来并做了标注;只提取这个 tree 里的命名实体:

print("Recognized named entities:")
for ne in ne_tagged:
    if hasattr(ne, "label"):
        print(ne.label(), ne[0:])
Recognized named entities:
PERSON [('Peterson', 'NNP')]
FACILITY [('Palo', 'NNP'), ('Alto', 'NNP')]
GPE [('California', 'NNP')]

图形化地显示:

ne_tagged.draw()

 title=

NLTK 内置的 命名实体标注器 named-entity tagger ,使用的是宾州法尼亚大学的 Automatic Content Extraction(ACE)程序。该标注器能够识别 组织机构 ORGANIZATION 、人名 PERSON 、地名 LOCATION 、设施 FACILITY 地缘政治实体 geopolitical entity 等常见 实体 entites

NLTK 也可以使用其他 标注器 tagger ,比如 Stanford Named Entity Recognizer. 这个经过训练的标注器用 Java 写成,但 NLTK 提供了一个使用它的接口(详情请查看 nltk.parse.stanfordnltk.tag.stanford)。

自主尝试

使用 Python 库,下载维基百科的 “open source” 页面,并识别出对 开源 open source 有影响力的人的名字,以及他们为 开源 open source 做贡献的时间和地点。

高级实践

如果你准备好了,尝试用这篇文章以及此前的文章介绍的知识构建一个 超级结构 superstructure

使用 Python 库,下载维基百科的 “Category: Computer science page”,然后:

  • 找出其中频率最高的 单词 unigrams 、二元搭配 bigrams 三元搭配 trigrams ,将它们作为一个关键词列表或者技术列表。相关领域的学生或者工程师需要了解这样一份列表里的内容。
  • 图形化地显示这个领域里重要的人名、技术、日期和地点。这会是一份很棒的信息图。
  • 构建一个搜索引擎。你的搜索引擎性能能够超过维基百科吗?

下一步?

自然语言处理是 应用构建 application building 的典型支柱。NLTK 是经典、丰富且强大的工具集,提供了为现实世界构建有吸引力、目标明确的应用的工作坊。

在这个系列的文章里,我用 NLTK 作为例子,展示了自然语言处理可以做什么。自然语言处理和 NLTK 还有太多东西值得探索,这个系列的文章只是帮助你探索它们的切入点。

如果你的需求增长到 NLTK 已经满足不了了,你可以训练新的模型或者向 NLTK 添加新的功能。基于 NLTK 构建的新的自然语言处理库正在不断涌现,机器学习也正被深度用于自然语言处理。


via: https://opensource.com/article/20/8/nlp-python-nltk

作者:Girish Managoli 选题:lujun9972 译者:tanloong 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

领域特定语言是在特定领域下用于特定上下文的语言。作为开发者,很有必要了解领域特定语言的含义,以及为什么要使用特定领域语言。

领域特定语言 domain-specific language (DSL)是一种旨在特定领域下的上下文的语言。这里的领域是指某种商业上的(例如银行业、保险业等)上下文,也可以指某种应用程序的(例如 Web 应用、数据库等)上下文。与之相比的另一个概念是 通用语言 general-purpose language (GPL,LCTT 译注:注意不要和 GPL 许可证混淆),通用语言则可以广泛应用于各种商业或应用问题当中。

DSL 并不具备很强的普适性,它是仅为某个适用的领域而设计的,但它也足以用于表示这个领域中的问题以及构建对应的解决方案。HTML 是 DSL 的一个典型,它是在 Web 应用上使用的语言,尽管 HTML 无法进行数字运算,但也不影响它在这方面的广泛应用。

而 GPL 则没有特定针对的领域,这种语言的设计者不可能知道这种语言会在什么领域被使用,更不清楚用户打算解决的问题是什么,因此 GPL 会被设计成可用于解决任何一种问题、适合任何一种业务、满足任何一种需求。例如 Java 就属于 GPL,它可以在 PC 或移动设备上运行,嵌入到银行、金融、保险、制造业等各种行业的应用中去。

DSL 的类别

从使用方式的角度,语言可以划分出以下两类:

  • DSL:使用 DSL 形式编写或表示的语言
  • 宿主语言 host language :用于执行或处理 DSL 的语言

由不同的语言编写并由另一种宿主语言处理的 DSL 被称为 外部 external DSL。

以下就是可以在宿主语言中处理的 SQL 形式的 DSL:

SELECT account
FROM accounts
WHERE account = '123' AND branch = 'abc' AND amount >= 1000

因此,只要在规定了词汇和语法的情况下,DSL 也可以直接使用英语来编写,并使用诸如 ANTLR 这样的 解析器生成器 parser generator 以另一种宿主语言来处理 DSL:

if smokes then increase premium by 10%

如果 DSL 和宿主语言是同一种语言,这种 DSL 称为 内部 internal DSL,其中 DSL 由以同一种语义的宿主语言编写和处理,因此又称为 嵌入式 embedded DSL。以下是两个例子:

  • Bash 形式的 DSL 可以由 Bash 解释器执行:
if today_is_christmas; then apply_christmas_discount; fi

同时这也是一段看起来符合英语语法的 Bash。

  • 使用类似 Java 语法编写的 DSL:
orderValue = orderValue
            .applyFestivalDiscount()
            .applyCustomerLoyalityDiscount()
            .applyCustomerAgeDiscount(); 

这一段的可读性也相当强。

实际上,DSL 和 GPL 之间并没有非常明确的界限。

DSL 家族

以下这些语言都可以作为 DSL 使用:

  • Web 应用:HTML
  • Shell:用于类 Unix 系统的 sh、Bash、CSH 等;用于 Windows 系统的 MS-DOS、Windows Terminal、PowerShell 等
  • 标记语言:XML
  • 建模:UML
  • 数据处理:SQL 及其变体
  • 业务规则管理:Drools
  • 硬件:Verilog、VHD
  • 构建工具:Maven、Gradle
  • 数值计算和模拟:MATLAB(商业)、GNU Octave、Scilab
  • 解析器和生成器:Lex、YACC、GNU Bison、ANTLR

为什么要使用 DSL?

DSL 的目的是在某个领域中记录一些需求和行为,在某些方面(例如金融商品交易)中,DSL 的适用场景可能更加狭窄。业务团队和技术团队能通过 DSL 有效地协同工作,因此 DSL 除了在业务用途上有所发挥,还可以让设计人员和开发人员用于设计和开发应用程序。

DSL 还可以用于生成一些用于解决特定问题的代码,但生成代码并不是 DSL 的重点并不在此,而是对专业领域知识的结合。当然,代码生成在领域工程中是一个巨大的优势。

DSL 的优点和缺点

DSL 的优点是,它对于领域的特征捕捉得非常好,同时它不像 GPL 那样包罗万有,学习和使用起来相对比较简单。因此,它在专业人员之间、专业人员和开发人员之间都提供了一个沟通的桥梁。

而 DSL 最显著的缺点就在于它只能用于一个特定的领域和目标。尽管学习起来不算太难,但学习成本仍然存在。如果使用到 DSL 相关的工具,即使对工作效率有所提升,但开发或配置这些工具也会增加一定的工作负担。另外,如果要设计一款 DSL,设计者必须具备专业领域知识和语言开发知识,而同时具备这两种知识的人却少之又少。

DSL 相关软件

开源的 DSL 软件包括:

  • Xtext:Xtext 可以与 Eclipse 集成,并支持 DSL 开发。它能够实现代码生成,因此一些开源和商业产品都用它来提供特定的功能。用于农业活动建模分析的 多用途农业数据系统 Multipurpose Agricultural Data System (MADS)就是基于 Xtext 实现的一个项目,可惜的是这个项目现在已经不太活跃了。
  • JetBrains MPS:JetBrains MPS 是一个可供开发 DSL 的 集成开发环境 Integrated Development Environment ,它将文档在底层存储为一个抽象树结构(Microsoft Word 也使用了这一概念),因此它也自称为一个 投影编辑器 projectional editor 。JetBrains MPS 支持 Java、C、JavaScript 和 XML 的代码生成。

DSL 的最佳实践

如果你想使用 DSL,记住以下几点:

  • DSL 不同于 GPL,DSL 只能用于解决特定领域中有限范围内的问题。
  • 不必动辄建立自己的 DSL,可以首先尝试寻找已有的 DSL。例如 DSLFIN 这个网站就提供了很多金融方面的 DSL。在实在找不到合适的 DSL 的情况下,才需要建立自己的 DSL。
  • DSL 最好像平常的语言一样具有可读性。
  • 尽管代码生成不是一项必需的工作,但它确实会大大提高工作效率。
  • 虽然 DSL 被称为语言,但 DSL 不需要像 GPL 一样可以被执行,可执行性并不是 DSL 需要达到的目的。
  • DSL 可以使用文本编辑器编写,但专门的 DSL 编辑器可以更轻松地完成 DSL 的语法和语义检查。

如果你正在使用或将要使用 DSL,欢迎在评论区留言。


via: https://opensource.com/article/20/2/domain-specific-languages

作者:Girish Managoli 选题:lujun9972 译者:HankChow 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

6 位专家为你解析 DevOps 及其实现、实践和哲学的关键。

如果你问 10 个人关于 DevOps 的问题,你会得到 12 个答案。这是对于 DevOps 的意见和期望的多样性的结果,更不用说它在实践中的差异。

为了解读 DevOps 的悖论,我们找到了最了解它的人 —— 这个行业的顶尖从业者。这些人熟悉 DevOps,了解技术的来龙去脉,并且已经有了多年 DevOps 实践。他们的观点应该能鼓励、刺激和激发你对 DevOps 的想法。

DevOps 对你意味着什么?

让我们从基本原理开始。我们不能只在教科书上寻找答案,而应该需要知道专家们怎么说。

简而言之,专家们说的是关于 DevOps 的原则、实践和工具。

IBM 数字企业集团 DevOps 商业平台领导者 Ann Marie Fred,说,“对于我来说,DevOps 是一套实践和原则,旨在使团队在设计、开发、交付和操作软件方面有更好的效率。”

据红帽资深 DevOps 布道者 Daniel Oh,“通常来说,DevOps 促使企业基于当前的 IT 发展与应用开发、IT 运维和安全协议的流程和工具。”

Tactec 战略解决方案的创始人 Brent Reed,谈及了利益相关者的持续改进,“DevOps 对我来说意味着包括了一种思维方式的工作方式,它允许持续改进运维绩效,进而提升组织绩效,从而让利益相关者受益。”

许多专家也强调 DevOps 文化。Ann Marie 说,“这也是持续改进和学习的问题。它涉及的是人和文化,以及工具和技术。”

美国保监会 (NAIC) 首席架构师兼 DevOps 领导者 Dan Barker,“DevOps 主要是关于文化…它将几个独立的领域聚集在一起,如精益生产、公正文化 和持续的学习。我认为文化是最关键和最难执行的。”

Atos 的 DevOps 负责人 Chris Baynham-Hughes,说,“[DevOps] 实践是通过组织内的文化、流程和工具的发展而被采用的。重点是文化变革,DevOps 文化借鉴的关键是协作、试验、快速反馈和持续改进。”

云架构师 Geoff Purdy,谈及敏捷和反馈,“缩短和放大反馈回路。我们希望团队在几分钟内而不是几周内获得反馈。”

但在最后,Daniel 通过解释开源和开源文化是如何让他以简单快捷的方式实现目标来强调这点,“在推动 DevOps 中,最重要的事情应该是开源文化而不是具体的工具或复杂的解决方案。”

你认为哪些 DevOps 实践有效?

专家列举的那些最佳实践是普遍存在的,但又各不相同。

Ann Marie 表示:“一些十分强大灵活的项目管理[实践],能在职能、独立的小组之间打破壁垒;全自动化持续部署,蓝/绿部署实现零时间停机状态;开发人员设置自己的监控和警告,无缝自我修复,自动化的安全性与合规性。”

Chris 说,“特别的突破是倾情合作、持续改进、开放领导、缩短业务距离、从垂直孤岛转向横向/跨功能的产品团队、工作透明化、相互影响、Mobius 循环、缩短反馈回路、自动化(从环境到 CI/CD)。”

Brent 支持“发展学习文化,包括 TTD [测试驱动开发] 和 BDD [行为驱动开发]捕获事件,并通过持续集成和持续交付从设计、构建和测试到实施在生产环境上一系列事件的自动化。测试采用故障优先的方法,能够自动化集成和交付流程,并在整个生命周期中包含快速反馈。”

Geoff 强调自动化配置。“选择一个自动化配置,对我的团队来说非常有效。更具体地说从版本控制代码库中自动配置。”

Dan 则玩的开心,“ 我们做了很多不同的事情来建立 DevOps 文化。我们举办 ‘午餐 & 学习’ 活动,提供免费的食物来鼓励大家一起学习。我们买书,分组学习。”

你如何激励你的团队实现 DevOps 这个目标?

Daniel 强调“自动化的问题就是为了减少 DevOps 计划中来自多个团队的异议,你应该鼓励你的团队提高开发、测试与 IT 运营的自动化能力,以及新的流程和程序。例如,Linux 容器是实现 DevOps 自动化功能的关键工具。”

Geoff 很是赞同,“机械化的劳作,你有讨厌现在做的任务吗?很棒。如果可能的话,让它们消失。不行,那就让它们自动化。它能使工作不会变得太枯燥,因为工作总是在变化。”

Dan、Ann Marie 和 Brent 强调团队的执行力。

Dan 说,“在 NAIC,我们有个很好的奖励系统来鼓励特定的行为。我们有多个级别的奖项,其中两个奖项可以由任何人颁布给某人。我们也会颁奖给完成重要任务的团队,但我们通常只奖励给个人贡献者。”

Ann Marie 表示,“我所在地区的团队最大的动力是看见其他人成功。我们每周都会彼此回放一次,其中一部分是分享我们从尝试新工具或实践中学到的东西。团队热衷于他们现在做的事情,并愿意帮助其他人开始,相信更多的团队很快也会加入进来。”

Brent 表示赞同。“让每个人学习,并掌握同样的基础知识至关重要……我喜欢从评估什么能帮助团队实现目标[以及]产品负责人和用户需要提供的内容入手。”

Chris 推荐采用双管齐下的方法。“运行可以每周可以实现的小目标,并且[在这]可以看到他们正在运做的功能工作之外的进展,庆祝你所取得的进步。”

DevOps 和敏捷开发如何协同工作?

这是一个重要的问题,因为 DevOps 和敏捷开发都是现代软件开发的基石。

DevOps 是一个软件开发的过程,专注与沟通与协作,以促进快速部署应用程序和产品。而敏捷开发是一种开发方法,涉及持续开发、连续迭代和连续测试,以实现可预测和可交付的成果质量。

那么,它们又有怎样的联系?让我们去问问专家吧。

在 Brent 来看,“DevOps != 敏捷。其次 敏捷 != Scrum 流程……敏捷工具和工作方式支撑着 DevOps 策略和目标,它们是如此融合在一起的。”

Chris 说,“对我而言敏捷是 DevOps 的一个基本组件。当然,我们可以讨论如何在非敏捷开发环境中采用 DevOps 文化,但最终表明,提高软件设计方式的灵活性是采用 DevOps 成熟读的一个关键指标。”

Dan 将 DevOps 与更伟大的 敏捷宣言 联系起来。“我在谈到敏捷时总会引用敏捷宣言来设置基准,而有许多实现中并不关注该宣言。当你阅读这份宣言时,你会发现它确实从开发的角度描述了 DevOps。因此,将敏捷融入 DevOps 文化非常容易,因为敏捷关注于沟通、协作、变化的灵活性以及快速地投入生产。”

Geoff 认为 “DevOps 是敏捷实施的众多实现之一。敏捷本质上是一套原则,而 DevOps 则是体现这些原则的文化、流程和工具链。”

Ann Marie 简洁说明,“敏捷是 DevOps 的先决条件。DevOps 使敏捷变得更加有效。”

DevOps 是否受益于开源?

这个问题得到了所有参与者的热烈肯定,然后解释了他们看到的好处。

Ann Marie 说,“我们站在巨人的肩膀上,在已有的基础之上发展。拉取请求和代码评审的开源模式,对 DevOps 团队维护软件很有效果。”

Chris 赞同 DevOps “毫无疑问”受益于开源。“从设计和工具方面(例如,Ansible),到流程和人员方面,通分享行业内的故事和开源社区的领导。”

Geoff 提到一个好处是“基层的采纳”。免费的软件不需要签署购买申请。团队发现了满足他们需求的工具,可以自行进行修改。[然后]在它之上构建,并为更大的社区提供更好的功能。如此往复。

开源已经向 DevOps 展示着“就像开源软件开发者正在做的那样,采用更好的方式来克服新的变化”,Daniel 说。

Brent 同意道 “DevOps 从开源中获益良多。一种方法是使用这些工具来理解它们是如何加速 DevOps 的目标和策略;在自动化、自动伸缩、虚拟化和容器化等关键方面对开发人员和操作人员进行培训,如果不引入使 DevOps 更加容易的技术支持,就很难实现这些特性。”

Dan 指出了 DevOps 和开源之间的双向共生关系,“做好开源需要 DevOps 文化。大多数开源项目都具有非常开放的沟通结构,很少有不透明的地方。对于 Devops 实践者来说,这实际上是一个很好的学习机会,可以让他们了解到可能需要将什么引入自己的组织中。此外能够使用来自社区与组织类似的工具来鼓励自己的文化成长。我喜欢用 GitLab 作为这种共生关系的一个例子。当我把 GitLab 带入一家公司时,我们得到了一个很棒的工具,但我们真正购买的是他们独特的文化,通过我们与他们的互动以及我们的贡献带来了巨大价值。他们的工具也可以为 DevOps 组织提供更多东西,而他们的文化已经在我引入它的公司中引起了他们的敬畏。”

现在我们的 DevOps 专家已经参与进来了,请在评论中分享你对 DevOps 的理解,以及向我们提出其他问题。


via: https://opensource.com/article/19/1/what-does-devops-mean-you

作者:Girish Managoli 选题:lujun9972 译者:MZqk 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

想要提升你的 DevOps 效率吗?将基础设施当成你的 CI 流程中的重要的一环。

持续交付(CD)和持续集成(CI)是 DevOps 的两个众所周知的方面。但在 CI 大肆流行的今天却忽略了另一个关键性的 I: 基础设施 infrastructure

曾经有一段时间 “基础设施”就意味着 无头 headless 的黑盒子、庞大的服务器,和高耸的机架 —— 更不用说漫长的采购流程和对盈余负载的错误估计。后来到了虚拟机时代,把基础设施处理得很好,虚拟化 —— 以前的世界从未有过这样。我们不再需要管理实体的服务器。仅仅是简单的点击,我们就可以创建和销毁、开始和停止、升级和降级我们的服务器。

有一个关于银行的流行故事:它们实现了数字化,并且引入了在线表格,用户需要手动填写表格、打印,然后邮寄回银行(LCTT 译注:我真的遇到过有人问我这样的需求怎么办)。这就是我们今天基础设施遇到的情况:使用新技术来做和以前一样的事情。

在这篇文章中,我们会看到在基础设施管理方面的进步,将基础设施视为一个版本化的组件并试着探索 不可变服务器 immutable server 的概念。在后面的文章中,我们将了解如何使用开源工具来实现持续的基础设施。

 title=

实践中的持续集成流程

这是我们熟悉的 CI,尽早发布、经常发布的循环流程。这个流程缺少一个关键的组件:基础设施。

突击小测试:

  • 你怎样创建和升级你的基础设施?
  • 你怎样控制和追溯基础设施的改变?
  • 你的基础设施是如何与你的业务进行匹配的?
  • 你是如何确保在正确的基础设施配置上进行测试的?

要回答这些问题,就要了解 持续基础设施 continuous infrastructure 。把 CI 构建流程分为 代码持续集成 continuous integration code (CIc)和 基础设施持续集成 continuous integration infrastructure (CIi)来并行开发和构建代码和基础设施,再将两者融合到一起进行测试。把基础设施构建视为 CI 流程中的重要的一环。

 title=

包含持续基础设施的 CI 流程

关于 CIi 定义的几个方面:

  1. 代码

通过代码来创建基础设施架构,而不是通过安装。 基础设施如代码 Infrastructure as code (IaC)是使用配置脚本创建基础设施的现代最流行的方法。这些脚本遵循典型的编码和单元测试周期(请参阅下面关于 Terraform 脚本的示例)。

  1. 版本

IaC 组件在源码仓库中进行版本管理。这让基础设施的拥有了版本控制的所有好处:一致性,可追溯性,分支和标记。

  1. 管理

通过编码和版本化的基础设施管理,你可以使用你所熟悉的测试和发布流程来管理基础设施的开发。

CIi 提供了下面的这些优势:

  1. 一致性 Consistency

版本化和标记化的基础设施意味着你可以清楚的知道你的系统使用了哪些组件和配置。这建立了一个非常好的 DevOps 实践,用来鉴别和管理基础设施的一致性。

  1. 可重现性 Reproducibility

通过基础设施的标记和基线,重建基础设施变得非常容易。想想你是否经常听到这个:“但是它在我的机器上可以运行!”现在,你可以在本地的测试平台中快速重现类似生产环境,从而将环境像变量一样在你的调试过程中删除。

  1. 可追溯性 Traceability

你是否还记得曾经有过多少次寻找到底是谁更改了文件夹权限的经历,或者是谁升级了 ssh 包?代码化的、版本化的,发布的基础设施消除了临时性变更,为基础设施的管理带来了可追踪性和可预测性。

  1. 自动化 Automation

借助脚本化的基础架构,自动化是下一个合乎逻辑的步骤。自动化允许你按需创建基础设施,并在使用完成后销毁它,所以你可以将更多宝贵的时间和精力用在更重要的任务上。

  1. 不变性 Immutability

CIi 带来了不可变基础设施等创新。你可以创建一个新的基础设施组件而不是通过升级(请参阅下面有关不可变设施的说明)。

持续基础设施是从运行基础环境到运行基础组件的进化。像处理代码一样,通过证实的 DevOps 流程来完成。对传统的 CI 的重新定义包含了缺少的那个 “i”,从而形成了连贯的 CD 。

(CIc + CIi) = CI -> CD

基础设施如代码 (IaC)

CIi 流程的一个关键推动因素是 基础设施如代码 infrastructure as code (IaC)。IaC 是一种使用配置文件进行基础设施创建和升级的机制。这些配置文件像其他的代码一样进行开发,并且使用版本管理系统进行管理。这些文件遵循一般的代码开发流程:单元测试、提交、构建和发布。IaC 流程拥有版本控制带给基础设施开发的所有好处,如标记、版本一致性,和修改可追溯。

这有一个简单的 Terraform 脚本用来在 AWS 上创建一个双层基础设施的简单示例,包括虚拟私有云(VPC)、弹性负载(ELB),安全组和一个 NGINX 服务器。Terraform 是一个通过脚本创建和更改基础设施架构和开源工具。

 title=

Terraform 脚本创建双层架构设施的简单示例

完整的脚本请参见 GitHub

不可变基础设施

你有几个正在运行的虚拟机,需要更新安全补丁。一个常见的做法是推送一个远程脚本单独更新每个系统。

要是不更新旧系统,如何才能直接丢弃它们并部署安装了新安全补丁的新系统呢?这就是 不可变基础设施 immutable infrastructure 。因为之前的基础设施是版本化的、标签化的,所以安装补丁就只是更新该脚本并将其推送到发布流程而已。

现在你知道为什么要说基础设施在 CI 流程中特别重要了吗?


via: https://opensource.com/article/17/11/continuous-infrastructure-other-ci

作者:Girish Managoli 选题:lujun9972 译者:Jamskr 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

这 20 多个有用的命令可以增强你使用 Vim 的体验。

编者注:标题和文章最初称呼的 vi 编辑器,现已更新为编辑器的正确名称:Vim

Vim 作为一款功能强大、选项丰富的编辑器,为许多用户所热爱。本文介绍了一些在 Vim 中默认未启用但实际非常有用的选项。虽然可以在每个 Vim 会话中单独启用,但为了创建一个开箱即用的高效编辑环境,还是建议在 Vim 的配置文件中配置这些命令。

开始前的准备

这里所说的选项或配置均位于用户主目录中的 Vim 启动配置文件 .vimrc。 按照下面的说明在 .vimrc 中设置选项:

(注意:vimrc 文件也用于 Linux 中的全局配置,如 /etc/vimrc/etc/vim/vimrc。本文所说的 .vimrc 均是指位于用户主目录中的 .vimrc 文件。)

Linux 系统中:

  • Vim 打开 .vimrc 文件: vim ~/.vimrc
  • 复制本文最后的 选项列表 粘贴到 .vimrc 文件
  • 保存并关闭 (:wq)

(LCTT 译注:此处不建议使用 Vim 编辑 .vimrc 文件,因为很可能无法粘贴成功,可以选择 gedit 编辑器编辑 .vimrc 文件。)

Windows 系统中:

  • 首先,安装 gvim
  • 打开 gvim
  • 单击 “编辑” -> “启动设置”,打开 _vimrc 文件
  • 复制本文最后的 “选项列表” 粘贴到 _vimrc 文件
  • 单击 “文件” -> “保存”

(LCTT 译注:此处应注意不要使用 Windows 自带的记事本编辑该 _vimrc 文件,否则可能会因为行结束符不同而导致问题。)

下面,我们将深入研究提高 Vim 编辑效率的选项。主要分为以下几类:

  1. 缩进 & 制表符
  2. 显示 & 格式化
  3. 搜索
  4. 浏览 & 滚动
  5. 拼写
  6. 其他选项

1. 缩进 & 制表符

使 Vim 在创建新行的时候使用与上一行同样的缩进:

set autoindent

创建新行时使用智能缩进,主要用于 C 语言一类的程序。通常,打开 smartindent 时也应该打开 autoindent

set smartindent

注意:Vim 具有语言感知功能,且其默认设置可以基于文件中的编程语言来改变配置以提高效率。有许多默认的配置选项,包括 axs cindentcinoptionsindentexpr 等,没有在这里说明。 syn 是一个非常有用的命令,用于设置文件的语法以更改显示模式。

(LCTT 译注:这里的 syn 是指 syntax,可用于设置文件所用的编程语言,开启对应的语法高亮,以及执行自动事件 (autocmd)。)

设置文件里的制表符 (TAB) 的宽度(以空格的数量表示):

set tabstop=4

设置移位操作 >><< 的缩进长度(以空格的数量表示):

set shiftwidth=4

如果你更喜欢在编辑文件时使用空格而不是制表符,设置以下选项可以使 Vim 在你按下 Tab 键时用空格代替制表符。

set expandtab

注意:这可能会导致依赖于制表符的 Python 等编程语言出现问题。这时,你可以根据文件类型设置该选项(请参考 autocmd)。

2. 显示 & 格式化

要在每行的前面显示行号:

set number

要在文本行超过一定长度时自动换行:

set textwidth=80

要根据从窗口右侧向左数的列数来自动换行:

set wrapmargin=2

(LCTT 译注:如果 textwidth 选项不等于零,本选项无效。)

当光标遍历文件时经过括号时,高亮标识匹配的括号:

set showmatch

3. 搜索

高亮搜索内容的所有匹配位置:

set hlsearch

搜索过程中动态显示匹配内容:

set incsearch

搜索时忽略大小写:

set ignorecase

在打开 ignorecase 选项的条件下,搜索内容包含部分大写字符时,要使搜索大小写敏感:

set smartcase

例如,如果文件内容是:

test
Test

当打开 ignorecasesmartcase 选项时,搜索 test 时的突出显示:

test
Test

搜索 Test 时的突出显示:

test
Test

4. 浏览 & 滚动

为获得更好的视觉体验,你可能希望将光标放在窗口中间而不是第一行,以下选项使光标距窗口上下保留 5 行。

set scrolloff=5

一个例子:

第一张图中 scrolloff=0,第二张图中 scrolloff=5

提示:如果你没有设置选项 nowrap,那么设置 sidescrolloff 将非常有用。

Vim 窗口底部显示一个永久状态栏,可以显示文件名、行号和列号等内容:

set laststatus=2

5. 拼写

Vim 有一个内置的拼写检查器,对于文本编辑和编码非常有用。Vim 可以识别文件类型并仅对代码中的注释进行拼写检查。使用下面的选项打开英语拼写检查:

set spell spelllang=en_us

(LCTT 译注:中文、日文或其它东亚语字符通常会在打开拼写检查时被标为拼写错误,因为拼写检查不支持这些语种,可以在 spelllang 选项中加入 cjk 来忽略这些错误标注。)

6. 其他选项

禁止创建备份文件:启用此选项后,Vim 将在覆盖文件前创建一个备份,文件成功写入后保留该备份。如果不想保留该备份文件,可以按下面的方式关闭:

set nobackup

禁止创建交换文件:启用此选项后,Vim 将在编辑该文件时创建一个交换文件。 交换文件用于在崩溃或发生使用冲突时恢复文件。交换文件是以 . 开头并以 .swp 结尾的隐藏文件。

set noswapfile

如果需要在同一个 Vim 窗口中编辑多个文件并进行切换。默认情况下,工作目录是打开的第一个文件的目录。而将工作目录自动切换到正在编辑的文件的目录是非常有用的。要自动切换工作目录:

set autochdir

Vim 自动维护编辑的历史记录,允许撤消更改。默认情况下,该历史记录仅在文件关闭之前有效。Vim 包含一个增强功能,使得即使在文件关闭后也可以维护撤消历史记录,这意味着即使在保存、关闭和重新打开文件后,也可以撤消之前的更改。历史记录文件是使用 .un~ 扩展名保存的隐藏文件。

set undofile

错误信息响铃,只对错误信息起作用:

set errorbells

如果你愿意,还可以设置错误视觉提示:

set visualbell

惊喜

Vim 提供长格式和短格式命令,两种格式都可用于设置或取消选项配置。

autoindent 选项的长格式是:

set autoindent

autoindent 选项的短格式是:

set ai

要在不更改选项当前值的情况下查看其当前设置,可以在 Vim 的命令行上使用在末尾加上 ? 的命令:

set autoindent?

在大多数选项前加上 no 前缀可以取消或关闭选项:

set noautoindent

可以为单独的文件配置选项,而不必修改全局配置文件。需要的话,请打开文件并输入 :,然后键入 set命令。这样的话,配置仅对当前的文件编辑会话有效。

使用命令行获取帮助:

:help autoindent

注意:此处列出的命令仅对 Linux 上的 Vim 7.4 版本和 Windows 上的 Vim 8.0 版本进行了测试。

这些有用的命令肯定会增强您的 Vim 使用体验。你会推荐哪些其他有用的命令?

选项列表

复制该选项列表粘贴到 .vimrc 文件中:

" Indentation & Tabs
set autoindent
set smartindent
set tabstop=4
set shiftwidth=4
set expandtab
set smarttab
" Display & format
set number
set textwidth=80
set wrapmargin=2
set showmatch
" Search
set hlsearch
set incsearch
set ignorecase
set smartcase
" Browse & Scroll
set scrolloff=5
set laststatus=2
" Spell
set spell spelllang=en_us
" Miscellaneous
set nobackup
set noswapfile
set autochdir
set undofile
set visualbell
set errorbells

via: https://opensource.com/article/18/9/vi-editor-productivity-powerhouse

作者:Girish Managoli 选题:lujun9972 译者:idea2act 校对:apemost, wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出