该类中使用一个结构体tagContext,具体如下:
struct tagContext{
int nKey;//The key word
int **aContextArray;//The context array
int *aTagFreq;//The total number a tag appears
int nTotalFreq;//The total number of all the tags
struct tagContext *next;//The chain pointer to next Context
};
这个结构体的具体含义待补。
CcontextStat类的成员
2006-9-8的学习笔记
现在回到不能回避的CContextStat类上。这个类的具体作用暂时没看清楚,从操作的步骤来一点一点写吧,呵呵。
构造函数和析构函数就是初使化一些成员变量及释放相应的空间,并不真正的读入内容。Load函数用于读入上下文相关内容。相应文件的格式如下,第一个int型大小的数据为表的长度,读入到m_nTableLen中,然后为m_pSymbolTable分配大小为m_nTableLen的int型空间,并读入相应m_nTableLen个int型数据到m_pSymbolTable中。然后读上下文无关m_pContext链表中的内容。第一个int型数据为链表结点中的关键字pCur->nKey,第二个int型数据为结点的频率值pCur->nTotalFreq,接下来的m_nTableLen个int型数据为相应的每个标记类型的频率值,分别读入到pCur->aTagFreq中。接下来的m_nTableLen×m_nTableLen个int型数据是aContextArray的值,其中aContextArray是一个大小为m_nTableLen的int型指针数组,每个m_nTableLen[i]指向一个大小为m_nTableLen的int型数组。上下文无关内容m_pContext每个结点都通过next指针串起来直到文件结束。Save函数就是load的逆过程,依上文所述之格式写入文件即可,这里不再详述,唯一注意的就是新添了一个以文本格式记录了文件的内容以供查看和参考。
对于该类的修改性函数还有Add,即添加一个新的结点,传入的参数分别是该结点的关键字nKey,前一个符号的id,当前要插入的符号的id以及相应的频率值。先查找是否已存在相同nKey的结点,如果没有找到则新建一个插入到相应的位置,注意新建这个结点的所有频率值都被置为0,只有关键字为nKey。无论是否找到nKey结点,根据传入的符号nPrevSymbol和nCurSymbol分别在符号表中查找相应的索引值。如果没有找到则修改其符号(为nPrevSymbol-nPrevSymbol%256)重新查找一下。如果都找到了那么更新相应的频率值及总频率值。
SetTableLen函数顾名思义就是设置符号表的大小,即修改m_nTableLen的值,同时会发生变化的还有m_pSymbolTable所指空间等,但是这个函数中没有做原有空间的释放工作直接就赋空了不太合理可能造成内存泄漏,不过这个函数在目前的代码中没有用到,暂时未构造潜在的危害。
SetSymbol也有类似SetTableLen的问题,直接进行了内存拷贝memcpy,而没有考空m_pSymbolTable是否有足够的空间,传入的参数是否合法。
GetItem用于查找给定关键字nKey的上下文无关结点,返回其指针。如果找到了则返回true并将其指针记录在pItemRet中,如果没有找到则返回其前一个结点的指针并返回false。注意如果链表为空则前一个结点的指针为NULL。
GetFrequency就是查找给定关键字给定符号的频率值,通过查找m_pContext所带的链表找到相应的关键字所在的结点pFound,通过查找m_pSymbolTable找到相应的符号的索引nIndex,然后返回pFound->aTagFreq[nIndex]。如果没有找到则返回0。
GetContextPossibility函数则是获得上下文无关文法的相应概率值。基本的策略是从符号表中读取当前符号和前一个符号的索引值,从上下文无关文法链表中读入相应关键词所在的结点位置,如果没有找到相应的结点,或者没有找到上述两个符号,又或者结点对应的前一个符号的词性标注概率值为0,又或者结点对应的这两个符号的上下文无关概率值为0,则返回一个很小的概率值避免数据稀疏。否则,返回按经验公式计算得到的相应概率值,计算公式如下:
0.9*nPrevCurConFreq/nPrevFreq+0.1*nPrevFreq/pCur->nTotalFreq;nPrevCurConFreq=pCur->aContextArray[nPrevIndex][nCurIndex];nPrevFreq=pCur->aTagFreq[nPrevIndex];其中
注意上述公式中计算时要将整型数据强制转换为double型数据,否则除法的结果会有问题。另外0.9和0.1都是经验值。
CContextStat类的总结。
至此,CContextStat类的函数就写完了。总的来说,这个类提供关于上下文无关文法的概率计算操作。