如何快速学习Scala

原文地址:GETTING STARTED

学习Scala语言最好的方法取决于你的知识储备和你的学习习惯。现在已经有了大量关于Scala的资料,如书籍、教程、训练语料、介绍和课程等。很多人找到一本关于Scala的书,并且马上开始使用Scala编译器去尝试Scala的例子。另一方面,你可能想使用线上有效的语料使用Scala进行训练。
正如你所了解的,Scala迅速的成长,现在已经有了更多先进的资料和友好的Scala社区,这里很多人都展示出了对Scala的热情以及对新人的欢迎。很多人写了很多关于Scala的有用的资料,并且很愿意通过Email回复关于技术上的问题,在Scala论坛和一些个人博客上也有介绍先进的概念和工具。

0. 初学者建议

如果你现在想开始学习如何编程,你能找到大量的关于Scala的资料,当然这个在你有一定编程经验的前提下的。下面我们推荐两个有价值的资料给Scala初学者,这将直接带你进入Scala的世界:

  • 在coursera上的在线课堂。由Scala的创始人Martin Odersky进行讲授。这套在线课程从学术的角度讲授了函数式编程。你将能通过解决函数式任务学习到很多Scala知识。
  • Kojo是一个交互式学习环境,你可以通过使用Scala编程去探索和完成数学、艺术、音乐、动画和游戏。

1. 开始Scala编程

1.1 “Hello World!”

在第一个示例里,我们使用标准的”Hello World!”程序去展示Scala的用法,这不需要有太多了Scala语言知识。

1
2
3
4
5
object HelloWorld {
def main(args: Array[String]): Unit = {
println("Hello, world!")
}
}

这种编程风格可能对Java程序员来说比较熟悉:包含main方法,可以打印标准输出。
我们假设已经正确设置Scala软件和用户运行环境。比如:

  • Unix
  • $SCALA_HOME /usr/local/share/scala
  • $PATH $PATH:$SCALA_PATH/bin
  • Windows
  • %SCALA_HOME% c:\Progra~1\Scala
  • %PATH% %PATH%;%SCALA_HOME%\bin

1.2 交互的方式运行

“scala”这一命令可以开始一个交互式shell,以交互式运行Scala代码。
Scala-HelloWorld
“:q”是命令”:quit”的缩写,可以退出Scala shell环境。

1.3 编译文件

“scalac”命令可以实现编译一个或多个Scala源文件,并且能生成标准的JVM可运行的Java二进制文件。Scala编译器的工作原理与Java SDK编译器”javac”类似。

1
> scalac HelloWorld.scala

通过默认的”scalac”在默认路径下生成类文件,你也可以通过”-d”这一参数制定一个不同的输出路径。

1
> scalac -d classes HelloWorld.scala

1.4 执行文件

“scala”命令可以通过正确的方法执行生成的二进制文件:

1
> scala HelloWorld

“scala”命令允许我们指定命令选项,比如:-classpath (-cp) 选项

1
> scala -cp classes HelloWorld

“scala”命令的对象必须是最高级别的。如果对象继承了App特征,那么所有包含在这个对象中的语句都会被执行;否则你必须添加一个”main”方法,这一方法扮演着你的程序入口的角色。
下面是”Hello, world!”程序示例继承App特征的样子:

1
2
3
object HelloWorld extends App {
println("Hello, world!")
}

1.5 使用脚本运行

我们也可能使用shell脚本或者”batch”命令运行我们的例子。
使用”bash shell”脚本”script.sh”包含如下的Scala代码:

1
#!/bin/sh
exec scala "$0" "$@"
!#
object HelloWorld extends App {
  println("Hello, world!")
}
HelloWorld.main(args)

可以直接被如下命令执行:

1
> ./script.sh

注意:我们假定script.sh文件中scala命令已经在PATH环境变量中声明。

机器学习实战-KNN

KNN
k-近邻算法(knn)是机器学习分类算法中最简单而且相当高效的算法,它的主要思想就是,选择与测试样本最相似的前K个训练样本,其中同一标签个数最多的标签就是测试样本的结果。一般来说,我们只选择样本数据集中前K个最相似的数据,这就是knn算法中k的出处,通常k是不大于20的整数。
下面我们使用Python语言实现简单的knn分类算法(按照《机器学习实战》),代码如下:

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
from numpy import *
import operator

def createDataSet():
group = array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]])
labels = ['A', 'A', 'B', 'B']
return group, labels

def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
diffMat = tile(inX, (dataSetSize, 1)) - dataSet
sqDiffMat = diffMat ** 2
sqDistances = sqDiffMat.sum(axis = 1)
distances = sqDistances ** 0.5
sortedDistIndicies = distances.argsort()
classCount = {}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
sortedClassCount = sorted(classCount.iteritems()\
, key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]

def file2matrix(filename):
fr = open(filename)
arrayOLines = fr.readlines()
numberOfLines = len(arrayOLines)
returnMat = zeros((numberOfLines, 3))
classLabelVector = []
index = 0
for line in arrayOLines:
line = line.strip()
listFromLine = line.split('\t')
returnMat[index,:] = listFromLine[0:3]
classLabelVector.append(int(listFromLine[-1]))
index += 1
return returnMat, classLabelVector

def autoNorm(dataSet):
minVals = dataSet.min(0)
maxVals = dataSet.max(0)
ranges = maxVals - minVals
normDataSet = zeros(shape(dataSet))
m = dataSet.shape[0]
normDataSet = dataSet - tile(minVals, (m, 1))
normDataSet = normDataSet / tile(ranges, (m, 1))
return normDataSet, ranges, minVals

def datingClassTest(k):
hoRatio = 0.10
datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
normMat, ranges, minVals = autoNorm(datingDataMat)
m = normMat.shape[0]
numTestVecs = int(m * hoRatio)
errorCount = 0.0
for i in range(numTestVecs):
classifierResult = classify0(normMat[i,:], normMat[numTestVecs:m,:],
datingLabels[numTestVecs:m], k)
print "The classifier came back with: %d, the real answer is: %d"\
% (classifierResult, datingLabels[i])
if classifierResult != datingLabels[i] : errorCount += 1.0
print "The total error rate is: %f" % (errorCount / float(numTestVecs))

knn算法比较简单,并且使用python语言,所以可以很快地实现该算法。动手跟着《机器学习实战》这本书敲了一遍代码之后,对knn的理解更加深入了一点。千里之行,始于足下。

Java参数传递

Java
最近使用Java语言实现一些服务,Java语言在传递参数时与C++不同,C++传递参数有三种格式(传值,传指针,传引用),按道理来说Java也应该有传值和传引用之分。然而,Java不同的是传递参数时,传值和引用的格式相同,没有特殊字符作为标记(C++,&)。这样就给很多程序员们带来了一定的困扰。首先请看如下代码和运行结果:

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
31
32
33
34
public static void main(String[] args) {
// TODO Auto-generated method stub
int n = 0;
StringBuffer sb1 = new StringBuffer("00");
StringBuffer sb2 = new StringBuffer("00");
sb3 = new StringBuffer("00");
change_int(n);
System.out.println(n);
change_String1(sb1);
System.out.println(sb1);
change_String2(sb2);
System.out.println(sb2);
change_String3(sb3);
System.out.println(sb3);
}

public static void change_int(int n) {
n = 1;
}

public static void change_String1(StringBuffer s) {
s.append("11");
}

public static void change_String2(StringBuffer s) {
s = new StringBuffer("00");
s.append("11");
}

public static void change_String3(StringBuffer s) {
s.append("33");
s = new StringBuffer("00");
s.append("11");
}

运行结果如下所示:
result
下面我们分析一下产生这样运行结果的原因。
Java在传递参数时,全部传的是引用,但是在传基本类型时,等号的赋值相当于重新声明了一个参数,比如在chang_String2函数中的StringBuffer若改成String类型,在函数内部重新赋值给String的话,运行该函数时,原来的值是不变的。
所以我们可以认为函数传入基本类型的参数时,是传的参数的拷贝,而传入一个对象时,是传入的引用。如果在函数内部对传入的引用进行更改,则原参数就会跟着变化,如果不改变传入的引用处的值,则不变,可以对比change_String2和change_String3两个函数。

LSTM Neural Networks for Chinese Word Segmentation

0.摘要

现在绝大多数的先进的中文分词方法都是基于有监督学习,其特征多数从本地文本中提取。这些方法不能利用一些至关重要的长距离的信息。在本篇文章中,我们发表了一篇对于中文分词的神经网络模型,它采用了长短记忆(LSTM)网络将先前的重要信息保存在记忆细胞中,并且避免了本地文本窗口的限制。实验在PKU,MSRA和CTB6人工标注的训练集,并展现出了比以往先进模型更出色的表现。

1.介绍

分词是中文自然语言处理中的一项基本任务。近些年,中文分词(CWS)的到了巨大的发展。流行的方法是将分词任务视为序列标记的问题。序列标注的目标是给序列中每一个元素分配标签,使用最大熵(ME)和条件随机场(CRF)等有监督学习算法可以实现。然而,这些模型受制于特征的设计,并且特征种类繁多以至于结果模型太大不利于实际应用,还被证明对于训练语料会产生过拟合。

RNN for NLP

背景

近些年,深度学习备受关注,这一前沿技术将在众多NLP问题上大放异彩,如预言模型,机器翻译,语音识别,语义理解等。然而解决这些应用上的问题,还需要人们不断探索与研究。本文将借鉴一些论文以及网上一些博客上的思想,如有侵权请给我留言,以便及时更正。
本篇文章将讨论RNN解决NLP中序列标注问题的优化。序列标注是NLP领域中有代表性的任务,可以解决中文分词,命名实体识别,词性标注等经典问题。解决序列标注问题的传统方法有CRF、最大熵等。随着深度学习技术的不断发展,深度学习将逐渐地取代传统方法。

序列标注

如上文所描述,一些NLP的问题可以转化为序列标注任务,所谓“序列标注”,就是说对于一个一维线性输入序列:

1
X = x1, x2, x3,..., xi,..., xn

得到标签集合中每个元素对应的标签:

1
Y = y1, y2, y3,..., yi,..., yn

所以,其本质上是对线性序列中每个元素根据上下文内容进行分类问题。一般情况下,对于NLP任务来说,线性序列就是输入的文本,往往可以把一个汉字看做线性序列中的一个元素,而不同标签集合对应的任务可能不想同。但是归根结底,都是抽象成了一个问题:如何根据汉字的上下文给汉字打上一个合适的标签。
下面再用命名实体识别(NER)问题举个序列标注解决问题的例子,命名实体识别任务是识别句子中出现的实体,通常识别人名、地名、机构名这三类实体。假设输入中文句子如下:

1
{花园北路的北医三院里,昏迷三年的我听杨幂的爱的供养时起身关了收音机。}

首先,我们将其看做汉字线性序列,然后我们定义标签集合:

1
LabelSet={BA, MA, EA, BO, MO, EO, BP, MP, EP, O}

其中,BA代表这个汉字是地址首字,MA代表这个汉字是地址中间字,EA代表这个汉字是地址的尾字;BO代表这个汉字是机构名的首字,MO代表这个汉字是机构名称的中间字,EO代表这个汉字是机构名的尾字;BP代表这个汉字是人名首字,MP代表这个汉字是人名中间字,EP代表这个汉字是人名尾字,而O代表这个汉字不属于命名实体。
有了输入序列和标签集合,我们只需要通过已有语料训练出ML模型,对于新的文本序列可以得到对应的标签,再通过后处理,把人名,地名,机构名都明确标记出来。如下图所示:
NER

RNN解决序列标注问题

首先用RNN解决序列标注问题,然后可以通过LSTM或者GRU来代替RNN中的隐藏单元,因为LSTM或GRU对于解决长距离依赖问题明显优于RNN本身。如果训练数据规模不大的情况下,很可能出现过拟合现象,所以使用LSTM的时候记得用上DropOut以及L1/L2正则来避免过拟合。至于GRU和LSTM两者相比,到底哪个更好目前并无定论,倾向于认为两者性能差不多,但是GRU是LSTM的简化模型,所以同样结构的神经网络其参数要少,在训练数据不太大情况下,优先考虑使用GRU。

参考文献

使用RNN解决NLP中序列标注问题的通用优化思路

Java_Entity

简介

Map是Java中的借口,Map.Entry是Map的一个内部借口。java.util.Map.Entry接口主要就是在遍历Map的时候用到。
Map提供了一些常用方法,如keySet(), entrySet()等方法,keySet()方法返回值是Map中key值的集合;entrySet()的返回值也是返回一个Set集合,此集合的类型为Map.Entry。
Map.Entry是Map声明的一个内部接口,此接口为泛型,定义为Entry。它表示Map中的一个实体(一个key-value对)。接口中有getKey(), getValue()方法。

示例

1
2
3
4
5
List<ServerAddress> addrs = new ArrayList<ServerAddress>();
Set<Entry<String, Integer>> entrySet = addressMap.entrySet();
for (Entry<String, Integer> entry : entrySet) {
addrs.add(new ServerAddress(entry.getKey(), entry.getValue()));
}