本文作者:张华千、滕桂法、刘小利 单位:河北农业大学

1、朴素贝叶斯实现新闻分类的步骤

引言

随着短信平台使用人数的增加,短信量呈几何数量增长,传统的工作模式在面对海量信息以及处理重复或冗余信息方面显的力不从心。专家要花去大量时间处理重复性的问题,系统的工作效率将为变得很低,专家资源得不到合理配置。因此,规范短信息服务,在整个智能应答短信平台的构建当中是极其重要的[2]。短信技术的低门槛性、短信平台的快捷性和高效性是值得肯定的。本文借鉴了垃圾短信过滤方面的经验,在原有农技推广短信平台的基础上,设计了一种具备智能应答功能的农技推广短信平台。

(1)提供文本文件,即数据集下载

 

智能应答短信平台

(2)准备数据

 
 手机短信在系统的应用中越来越广泛,从单纯的发送信息到手机,发展到接收手机发送的短信,进行信息的获取,更有甚者,还可以进行业务的变更,业务数据的
修改。从少量的发送,发展到大量的收发,衍生出大量的互动性短信。这就对短信收发的设计提出了更高的要求,不仅仅是简单的发送消息,不仅仅是简单的短信模
块,而且需要配合消息队列,短信路由子系统,业务编码规则等等技术来满足大量互动性短息的收发要求。

智能应答短信平台自上而下主要分为应用层和实现层、数据层和接入层。其中,应用层与实现层主要通过HTTP与WebService服务接口实现无缝接入;数据层负责管理短信平台相关数据库,将短信过滤和分类形成目标短信,并预留接口对接专家数据库以实现智能应答等扩展应用。三大通信运营商短信网关通过接入层与短信平台对接。体系结构如图1所示。应用层分布主要包括农技推广单位在信息化进程中建立起来的各种B/S和C/S结构的信息管理系统以及各类数据库系统。这些系统都有点对点或者点对多点的信息发布的需求,系统架构和编程语言不尽同,因此宜采用WebService技术实现这些异构系统到短信平台的统一接入。实现层根据业务与管理的联系将短信平台划分为诸多模块,做到了业务与管理形式上分离、逻辑上紧密联系。实现层不同功能模块通过不同的协议或算法实现其具体功能,如通过SMS(ShortMessagingService)协议处理短消息文本,MMS(MultimediaMes-sagingService)处理相关文本或图片请求,通过数据路由控制算法控制数据与运营商网关对接过程中具体的路由跳转方法,通过调度算法来协调各功能模块间业务逻辑。数据层为短信平台系统提供数据支撑与应用扩展。本文的关键即在数据层中进行改造,从而实现自动应答功能。数据层的核心是数据库接口模块。短信平台数据库及扩展应用服务通过数据库接口模块进行数据的通信和共享。短信分类器具备将海量短信分类并转化成可以与专家数据库进行完全或模糊匹配的标准短信的功能。接入层通过SMPP(ShortMessagePeertoPeer,短信息点对点协议)与移动通信运营商的短信网关通信。由于国内的三大电信运营商在互联网短信网关的通信上制定了不同的协议标准,如中国移动的CMPP协议、中国联通的SGIP协议和中国电信的SMGP协议。因此,在接入层相应地将接入模块分为中国移动接入模块、中国联通接入模块和中国电信接入模块,以保障不同手机号段的短信都能接入到相应的运营商网关中[3]。

     
   将数据集划分为训练集和测试集;使用jieba模块进行分词,词频统计,停用词过滤,文本特征提取,将文本数据向量化

 

传统的短信平台在农技推广中一般是以农户、短信平台和专家队伍“三点一线”的模式进行工作的。优点是业务模式简单、技术门槛低和易于操作;缺点是忽视了农户与专家知识水平上的巨大差距,没有全面地考虑到农户田间作业的季节性特点,最终往往形成农户对反馈短信的含义一知半解;专家对一个重复问题多次做出相同解释,浪费服务资源;农闲时专家工作较为轻松,农忙时问题量庞大,反馈结果难以实时反馈,农户长时间得不到专家的建议,造成经济损失。智能应答短信平台综合考虑了传统短信平台的优缺点,引入了短信分类与自动应答功能。传统短信平台工作统程如图2所示,智能应答短信平台工作流程如图3所示。对比图2和图3,不难看出传统短信平台与智能应答短信平台在工作流程上的不同之处。传统的短信平台中没有对于短信内容的判断,只是机械地接收。智能应答短信平台在海量短信到达短信平台之后首先进行短信内容的分类与过滤,之后通过扫描专家数据库进行自动应答工作,这样的工作模式更有针对性,也更加合理。

       
 停用词文本stopwords_cn.txt下载

1、短信收发类

智能应答短信平台具有传统短信平台的基本功能,同时具备自动应答功能,因此在农技推广中有更加广阔的应用前景。提供的主要服务有:面向农户的自助和实时咨询服务;个性化订制;群发信息服务;定时发送提醒服务;与农技推广应用系统集成(如气象系统、病虫害防治系统、农业信息化服务系统等)。

         jieba模块学习: ; 
  

 

关键技术解决方案

(3)分析数据:使用matplotlib模块分析

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
package com.andyshi;
import java.rmi.RemoteException;
import org.tempuri.WebServiceSoapProxy;
public class SMSManager {
    WebServiceSoapProxy client=new WebServiceSoapProxy();
                                                                                                                                                                                                                                
    public SMSManager(){
//      client.setEndpoint("http://sdk2.entinfo.cn/webservice.asmx");
    }
                                                                                                                                                                                                                                
                                                                                                                                                                                                                                
                                                                                                                                                                                                                                
    public void Receive(){
                                                                                                                                                                                                                                 
    }
                                                                                                                                                                                                                                
                                                                                                                                                                                                                                
    public void Send(){
        try {
            client.sendSMS("sdfsd", "sdfsf", "sdf", "sf");
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

智能应答短信平台需解决的关键技术包括专家数据库的建立[4]和短信分类器的设计。

(4)训练算法:使用sklearn.naive_bayes 的MultinomialNB进行训练

 

短信分类器借鉴了文本数据挖掘[5-6]、BP神经网络[7]、垃圾短信过滤相关方面的经验。短信分类是指根据一个己经被标注的训练短信集合,找到内容属性,然后利用这种学习得到的关系模型对新的短信进行类别判断。从数学的角度来看,短信分类是一个映射过程。映射规则f是系统根据已经掌握的每类若干样本的数据信息,总结出分类的规律性而建立的判别公式和判别规则,随着类别集合Y的不断扩充,映射规则f也相应随之改变。短信分类器的工作流程包括两大步,即分类规则建立和短信分类。首先,分类规则建立,给定训练短信集合;然后,把训练集的文本统一表示,常用的是向量空间模型表示法,再通过特征提取降维;最后,通过各种分类模型建立起一个分类规则;接着是短信分类过程,给定一条新短信,经过向量表示、特征提取后送入分类规则进行判断,输出该文本所属类别。对于分类结果不太明确的结果在人工神经网络中进行第2次竞争,对结果进行排序,筛选出最优分类结果。特征提取主要分4个步骤:短信预处理、分词、去噪和短信文本特征表示。短信预处理指根据短信内容处理一些乱码、符号等。一般通过编写正则表达式,根据实际需要进行贪婪或非贪婪的匹配,祛除一些诸如“#%*”之类的符号。分词的过程类似于验证码识别技术当中的分割技术,根据短信内容将短信文本切分为一些有意义关键词,目的是方便与专家数据库进行匹配。去噪处理指祛除或统一短信中含有“噪声的”数据,即删掉与短信真正要表达的含义相差比较远的数据。例如,祛除中文语气词“哎、啊、撒”和英文中的“hi,hello”,中文近义词“果子,水果”统一表示成水果。短信文本特征表示是将短信内容在特征空间中量化,方便后续的特征提取降维,筛选出真正可以传达农户意图的向量属性,进行分类。

       
 Sklearn构建朴素贝叶斯分类器官方文档学习

2、短信收发模块

智能应答短信平台中的专家数据库通过数据库接口模块与短信平台的数据库进行通信,是短信平台自身数据库的扩展。专家数据库的建立主要分为数据表的设计和触发器设计两个部分。专家数据库中的数据表字段主要分为待匹配问题、解决方案、查询率和优先级。

       
 在scikit-learn中,一共有3个朴素贝叶斯的分类算法类。分别是GaussianNB,MultinomialNB和BernoulliNB。

 

首先,应建立待匹配问题与相应解决方案对照数据表。待匹配问题字段的数据源来自短信平台,通过群发功能向广大农户征集的短信意见,通过短信分类器处理后存储在短信平台自身数据库中的记录以及资深专家在相关研究领域遇到的新问题或成果。待匹配问题字段只记录问题分类,通过分类索引与描述问题特征的数据表进行匹配。描述问题特征的数据表可以参考汉语行文习惯,采用主谓宾的方式插入数据。例如,某农户发送短信是“我家的枣树不知道为什么打了农药以后还是生虫子”,数据表中对应的3个字段为“枣树”、“生”和“虫子”。专家根据自身的时间安排,抽出集中时间登录短信平台进行统一作答,建立一个稍具规模的专家数据库。

       
其中GaussianNB就是先验为高斯分布的朴素贝叶斯,MultinomialNB就是先验为多项式分布的朴素贝叶斯,而BernoulliNB就是先验为伯努利分布的朴素贝叶斯。

 
 成为几个类的组合,Sender,Receiver,还有一些辅助的方法,而且输入输出也从简单类型变成了实体类,减少模块调用者的出错概率。

查询率是为了记录同一个或同一类问题最近一段时间被提问的次数与相同时间被提问总次数的比值百分化,通过设定一个阈值来衡量查询率。查询率高于阈值的被标记为热点问题,不等农户再频繁地询问,采用定时群发的方案,提醒广大农民引起注意;而查询率远低于阈值的被标记为冷门问题,在系统负荷量加重的时候,通过降低其优先级,暂不处理,使负载恢复平衡。

(5)测试算法:使用测试集对贝叶斯分类器进行测试

 

优先级可根据实际需要建立和查询率之间的算法,编写业务逻辑来实现控制优先级的大小,从而达到优化专家数据处理、相应的速率的目的。专家数据库中的触发器主要触发轮询时间控制器对短信平台自身数据库的扫描和短信平台代码模块中负责发送短信息的SendMessage()函数。轮询时间控制着专家数据库与短信平台自身数据库访问的频率。默认情况下,在农闲时可以将时钟周期设置较为长一些,在农忙的时候设置短一些,并以标志位flag标志激活状态。flag为0时,时间控制器处于休眠期;为1时,开始工作。当触发器满足轮询时间控制器的时钟周期时,自动将flag标志位置1,触发轮询时间控制器。轮询时间控制器扫描并读入短信平台自身数据库中记录送与短信分类器分类后,通过专家数据库给出解决建议,同时将该短信置为已读,下个时钟周期到来时不予处理。智能应答短信平台的自动应答功能是由专家数据库中的触发器触根据条件发SendMessage()函数后进行发送的,按优先级排列好的反馈结果被送入发送队列等候,根据触发器的触发条件通过SendMessage()函数发送至运营商网关进行后续处理。

 2、代码实现

变化

结束语

# -*- coding: UTF-8 -*-
import os
import random
import jieba
from sklearn.naive_bayes import MultinomialNB
import matplotlib.pyplot as plt

"""
函数说明:中文文本处理
Parameters:
    folder_path - 文本存放的路径
    test_size - 测试集占比,默认占所有数据集的百分之20
Returns:
    all_words_list - 按词频降序排序的训练集列表
    train_data_list - 训练集列表
    test_data_list - 测试集列表
    train_class_list - 训练集标签列表
    test_class_list - 测试集标签列表
"""
def TextProcessing(folder_path, test_size=0.2):
    folder_list = os.listdir(folder_path)  # 查看folder_path下的文件
    data_list = []  # 数据集数据
    class_list = []  # 数据集类别
    # 遍历每个子文件夹
    for folder in folder_list:
        new_folder_path = os.path.join(folder_path, folder)  # 根据子文件夹,生成新的路径
        files = os.listdir(new_folder_path)  # 存放子文件夹下的txt文件的列表
        j = 1
        # 遍历每个txt文件
        for file in files:
            if j > 100:  # 每类txt样本数最多100个
                break
            with open(os.path.join(new_folder_path, file), 'r', encoding='utf-8') as f:  # 打开txt文件
                raw = f.read()

            word_cut = jieba.cut(raw, cut_all=False)  # 精简模式,返回一个可迭代的generator
            word_list = list(word_cut)  # generator转换为list

            data_list.append(word_list)  # 添加数据集数据
            class_list.append(folder)  # 添加数据集类别
            j += 1
    data_class_list = list(zip(data_list, class_list))  # zip压缩合并,将数据与标签对应压缩
    random.shuffle(data_class_list)  # 将data_class_list乱序
    index = int(len(data_class_list) * test_size) + 1  # 训练集和测试集切分的索引值
    train_list = data_class_list[index:]  # 训练集
    test_list = data_class_list[:index]  # 测试集
    train_data_list, train_class_list = zip(*train_list)  # 训练集解压缩
    test_data_list, test_class_list = zip(*test_list)  # 测试集解压缩

    all_words_dict = {}  # 统计训练集词频
    for word_list in train_data_list:
        for word in word_list:
            if word in all_words_dict.keys():
                all_words_dict[word] += 1
            else:
                all_words_dict[word] = 1

    # 根据键的值倒序排序
    all_words_tuple_list = sorted(all_words_dict.items(), key=lambda f: f[1], reverse=True)
    all_words_list, all_words_nums = zip(*all_words_tuple_list)  # 解压缩
    all_words_list = list(all_words_list)  # 转换成列表
    return all_words_list, train_data_list, test_data_list, train_class_list, test_class_list


"""
函数说明:读取文件里的内容,并去重
Parameters:
    words_file - 文件路径
Returns:
    words_set - 读取的内容的set集合
"""
def MakeWordsSet(words_file):
    words_set = set()  # 创建set集合
    with open(words_file, 'r', encoding='utf-8') as f:  # 打开文件
        for line in f.readlines():  # 一行一行读取
            word = line.strip()  # 去回车
            if len(word) > 0:  # 有文本,则添加到words_set中
                words_set.add(word)
    return words_set  # 返回处理结果


"""
函数说明:文本特征选取
Parameters:
    all_words_list - 训练集所有文本列表
    deleteN - 删除词频最高的deleteN个词
    stopwords_set - 指定的结束语
Returns:
    feature_words - 特征集
"""
def words_dict(all_words_list, deleteN, stopwords_set=set()):
    feature_words = []  # 特征列表
    n = 1
    for t in range(deleteN, len(all_words_list), 1):
        if n > 1000:  # feature_words的维度为1000
            break
            # 如果这个词不是数字,并且不是指定的结束语,并且单词长度大于1小于5,那么这个词就可以作为特征词
        if not all_words_list[t].isdigit() and all_words_list[t] not in stopwords_set and 1 < len(all_words_list[t]) < 5:
            feature_words.append(all_words_list[t])
        n += 1
    return feature_words


"""
函数说明:根据feature_words将文本向量化
Parameters:
    train_data_list - 训练集
    test_data_list - 测试集
    feature_words - 特征集
Returns:
    train_feature_list - 训练集向量化列表
    test_feature_list - 测试集向量化列表
"""
def TextFeatures(train_data_list, test_data_list, feature_words):
    def text_features(text, feature_words):  # 出现在特征集中,则置1
        text_words = set(text)
        features = [1 if word in text_words else 0 for word in feature_words]
        return features

    train_feature_list = [text_features(text, feature_words) for text in train_data_list]
    test_feature_list = [text_features(text, feature_words) for text in test_data_list]
    return train_feature_list, test_feature_list  # 返回结果


"""
函数说明:新闻分类器
Parameters:
    train_feature_list - 训练集向量化的特征文本
    test_feature_list - 测试集向量化的特征文本
    train_class_list - 训练集分类标签
    test_class_list - 测试集分类标签
Returns:
    test_accuracy - 分类器精度
"""
def TextClassifier(train_feature_list, test_feature_list, train_class_list, test_class_list):
    classifier = MultinomialNB().fit(train_feature_list, train_class_list)
    test_accuracy = classifier.score(test_feature_list, test_class_list)
    return test_accuracy


if __name__ == '__main__':
    # 文本预处理
    folder_path = './SogouC/Sample'  # 训练集存放地址
    all_words_list, train_data_list, test_data_list, train_class_list, test_class_list = TextProcessing(folder_path,test_size=0.2)
    # 生成stopwords_set
    stopwords_file = './stopwords_cn.txt'
    stopwords_set = MakeWordsSet(stopwords_file)

    test_accuracy_list = []
    """
    deleteNs = range(0, 1000, 20)  # 0 20 40 60 ... 980
    for deleteN in deleteNs:
        feature_words = words_dict(all_words_list, deleteN, stopwords_set)
        train_feature_list, test_feature_list = TextFeatures(train_data_list, test_data_list, feature_words)
        test_accuracy = TextClassifier(train_feature_list, test_feature_list, train_class_list, test_class_list)
        test_accuracy_list.append(test_accuracy)
    plt.figure()
    plt.plot(deleteNs, test_accuracy_list)
    plt.title('Relationship of deleteNs and test_accuracy')
    plt.xlabel('deleteNs')
    plt.ylabel('test_accuracy')
    plt.show()
    """
    feature_words = words_dict(all_words_list, 450, stopwords_set)
    train_feature_list, test_feature_list = TextFeatures(train_data_list, test_data_list, feature_words)
    test_accuracy = TextClassifier(train_feature_list, test_feature_list, train_class_list, test_class_list)
    test_accuracy_list.append(test_accuracy)
    ave = lambda c: sum(c) / len(c)
    print(ave(test_accuracy_list))

1、从单个类变成了几个类的组合。

强化农技服务体系建设,提升农技推广与农业信息服务能力,是当前各级农技推广部门都在思考的问题。智能应答短信平台有其极为广阔的应用前景。本文主要针对农户海量短信分类进而自动应答的解决方案,没有涉及到彩信方面的自动应答,对于影响短信息传递、引起短信服务中心网络阻塞的原因研究的还不够透彻。尽管如此,相信随着3G技术的普及,国家在农业信息化方面的资金投入逐步加大,SP服务商开发更多应用服务来开发自己的用户,智能应答短信平台必将在农技推广方面为广大农民提供更加丰富的服务[8]。因此,就农业信息短信服务平台的合理性与准确性考虑,将物联网和云计算等新兴信息技术思想与短信平台相结合,是今后的一个研究方向。

  结果为:

职责单一。

图片 1

 

图片 2

2、增加辅助类。

 

例如短信实体的创建类。

因为收到的短信是字符串,而且可能是多条短信,所以增加了一些解析类,从字符串中解析出短信,生成短信实体。

 

3、输入输入

整个收发过程的输入输出从简单类型的变成了实体类,这样可以减少模块调用者出错的概率,对外更加内聚。

 

3、短信收发子系统

 

 
 随着短信收发量的增大,同步实时发送和接收已经不能满足要求。而且随着业务的增加,业务系统的增加,有很多地方都需要短信的收发功能,比如说短信验证,
短信查询,短信互动,订阅短信通知,群发短信,短信操作业务,短信变更业务数据。业务也从单纯的发,或者是少量的收,变成大量的收发处理。

 

 
 这时候需要考虑更多的东西,例如短信的实时性,可靠性,自动重发,优先级。需要将短信的收发和处理分开,需要消息队列的配合,将收到和需要发送的短信先存入消息队列,然后定时从消息队列获取,进行发送或者业务的处理。

 

4、短信收发平台

 

短信收发平台负责具体的短信收发工作,分离具体的业务处理,增加短信路由子系统。

 

短信有三个运营商:移动,联通,电信。

 

4.1 短信路由子系统

 
 1、短信平台收到短信之后,交给短信路由子系统,将收到的业务编码,按照业务编码规则路由到某个业务子系统,进行业务的处理。如果是指令性的短信,则不需要信息返回;如果是交互性的短信,业务子系统处理之后肯定还需要发送短信,发送短信给短信路由子系统。

 
 2、如果业务子系统需要发送短信,肯定是需要发送给一个手机号的,这个手机号只可能是具体的一个运营商的,但是业务子系统不用关心这些,它只是知道发送给一个手机号一段消息,然后交给短信路由子系统,短信路由子系统来决定经由那个运营商的通道发送到具体的手机号。

 

4.2 存储设计

 
 很多的短信都可以用模板+具体业务数据(例如祝福类短信,其中的用户名不一样,其他的内容都是一样的)的形式来表示,业务子系统负责存储模板和业务数据,这样可以减少很多冗余,而且需要修改短信内容的话,只需要修改模板就可以了。

短信平台存储完整的短信内容,方便查询统计。

 

4.3 其他

 
 随着短息量越来越大,子系统也会使用消息队列来缓存收发的消息,减轻具体业务的处理压力。

 

 

============================================

后记

==========

2013-08-14

 

发送子系统

接收业务系统来的短信,进行具体的发送工作。发送之前,可能需要区分通道,也就是短信是发给那个运营商的,之前是想交给路由子系统来实现的,但是觉得这个工作更应该是发送子系统来做的事情,路由子系统和业务还是有一点关系,至少还有一个业务匹配规则配置。

 

接收子系统

接收外部发送过来的短信。

 

路由子系统

路由和分解短信到具体的业务子系统,路由的规则包括特服号码(运营商或者是SP分配给短信业务申请者的一个号码)和短信业务的识别码。

比如说发送到100900的都是订单获取的业务,发送到100800都是个人信息获取的业务,发送到100700都是帮助获取的业务。

识别码也就是接收短信的内容,或者是内容的前几位数字。比如说接收到的内容是QX10000,那就是订单子系统的,用来取消(QX)订单,订单编号是10000。

相关文章