THUCTC源码解读(三)

时间:2022-12-28 10:00:59

Term类

Term也是一个非常简单的类,是文档向量(DocumentVector)的基本组成部分,一个Term表示词典中的一个词。
存储的变量只有id和weight, id表示该Term代表的词在词典中的id,而weight表示该词在文档向量中的权重。此外,Term的内部类TermIdComparator还实现了Comparator接口,使得java能够对Term数组进行排序。

public class Term {
public int id;
public double weight;

public static class TermIdComparator implements Comparator<Term>, Serializable {
public int compare(Term o1, Term o2) {
return o1.id - o2.id;
}

}
public static class TermWeightComparator implements Comparator<Term> {
public int compare(Term o1, Term o2) {
return Double.compare(o2.weight, o1.weight);
}
}
}

TermWeighter类

TermWeighter是一个抽象类,需要继承类实现对Term计算权重的功能。由于在THUCTC中使用了TF-IDF的权重计算方式,所以该类需要词典来提供一个词的TF和IDF值。

public abstract class TermWeighter implements Serializable{
protected Lexicon lexicon;

public TermWeighter( Lexicon l ) {
lexicon = l;
}

abstract public double weight ( int id, double tf, int doclen);
}

DocumentVector类

DocumentVector,就是将一篇文档向量化表示。文档向量的长度即为词典中单词数目,向量中第i个term表示词典中的第i个词在该文档向量中的权重。
DocumentVector本身并不存储向量内容,而是向外界提供了生成文档向量的方法。DocumentVector类中只有2个变量,分别是TermWeighter和Term.TermIdComparator对象,分别实现计算权重和term数组的排序功能。
除了构造方法外,该类只有两个方法,分别是build和dotProduct,前者负责将Word数组形式的文档转化成文档向量(Term数组),后者负责两个向量的内乘,这里主要看build方法

public Term [] build( Word [] doc, boolean normalized) {
// Term 为 id-weight 表示形式
Hashtable<Integer, Term> terms = new Hashtable<Integer, Term>();
// 这部分是统计各terms出现次数
for ( Word w : doc ) {
Term t = terms.get(w.id);
if ( t == null ) {
t = new Term();
t.id = w.id;
t.weight = 0;
terms.put(t.id, t);
}
t.weight += 1; // 出现次数+1
}

// 这部分是将hashtable转化成数组并使用TermWeighter计算权重
Term [] vec = new Term[terms.size()];
Enumeration<Term> en = terms.elements();//使用迭代的方法遍历,类似于Python中的迭代器
int i = 0;
double normalizer = 0;
while ( en.hasMoreElements() ) {
vec[i] = en.nextElement();
vec[i].weight =
weighter.weight( vec[i].id, vec[i].weight, doc.length);
normalizer += vec[i].weight * vec[i].weight;
i++;
}

if ( normalized ) { //如果normalized=true,则进行正则化计算
normalizer = Math.sqrt(normalizer);
for ( Term t : vec ) {
t.weight /= normalizer;
}
}

Arrays.sort(vec, idcomp); //这里通过TermIdComparator来实现对term数组的排序

return vec;
}

LinearBigramChineseClassifier类

这个类在Demo中出现过。虽然在demo中分类器是由BasicTextClassifier创建的,但是毫无疑问LinearBigramChineseClassifier是分类器的核心,BasicTextClassifier只是在此基础上的一层封装,实现了模型的导入导出,参数初始化等一些交互功能。

这个类继承自LiblinearTextClassifier,大部分内容由LiblinearTextClassifier实现,LiblinearTextClassifier是一个抽象类,因为其中有一个抽象的方法initWordSegment,而LinearBigramChineseClassifier实现了这个方法。

public class LinearBigramChineseTextClassifier extends LiblinearTextClassifier{

public LinearBigramChineseTextClassifier(int nclasses) {
super(nclasses);
}

public LinearBigramChineseTextClassifier(int nclasses, WordSegment seg ) {
super(nclasses, seg);
}

@Override
protected WordSegment initWordSegment() {
return new BilingualBigramWordSegment(); // 实现了父类中的抽象方法
}

}