用fasttext 训练

下载fasttext

官网: https://github.com/facebookresearch/fastText

编译 和安装

wget https://github.com/facebookresearch/fastText/archiv/v0.9.1.zip
unzip v0.9.1.zip
cd fastText-0.9.1
 make
 pip install .

使用fasttext

格式:

__label__Sociology , 年轻 男子 疑因 感情 受挫 旅馆 内 跳楼 身亡 新快报
__label__Technology , 18 倍 光变 27mm 广角 尼康 P80 套装 2800 元 作

喂给 fasttext 的文档必须是这样的格式: 前缀+标签 + 逗号 + 分词

__label__  这个是前缀
Sociology: 这个是标签
年轻 男子 疑因 感情   :这是中文分词 中间用空格隔开

变换数据

1,要将数据集 分成 训练集 和 测试集 第一步 将数据转换成 csv

方便后面的切割操作

2,将CSV数据 切割成 train.txt 和 test.txt

import fasttext

import re
from types import MethodType, FunctionType

import jieba

from collections import defaultdict

import  pandas  as pd

import  random
import  os

class TransformData(object):

    #将文档转换成 CSV
    def to_csv(self, inPath, outPath, index=False):
        dd = {}
        handler = open(inPath)


        for line in handler:
            label, content = line.split(',', 1)
            key =label.strip('__label__').strip()
            if not  dd.get(key,False):
                dd[key] =[]
            dd[key].append(content.strip())
        handler.close()

        df = pd.DataFrame()
        for key in dd.keys():
            col = pd.Series(dd[key], name=key)
            df = pd.concat([df, col], axis=1)
        return df.to_csv(outPath, index=index, encoding='utf-8')
    #切割数据集 成 train.txt  test.txt
    def  SplitTrainTest(self,inPath,splitRate=0.8):
         baseName = inPath.rsplit('.',1)[0]
         trainFile = baseName + '_Train.txt'
         testFile = baseName+"_Test.txt"
         handle = pd.read_csv(inPath,index_col=False,low_memory=False)
         trainDataSet=[]
         testDataSet=[]
         for head  in list(handle.head()):
              print("head==",head,handle[head].dropna())
              trainNub= int(handle[head].dropna().__len__()*splitRate)
              subList=[f"__label__{head} , {item.strip()}\n" for item in handle[head].dropna().tolist()]
              trainDataSet.extend(subList[:trainNub])
              testDataSet.extend(subList[trainNub:])
              print("subList=",subList)

         random.shuffle(trainDataSet)
         random.shuffle(testDataSet)
         with open(trainFile, 'w', encoding='utf-8') as trainf, \
                 open(testFile, 'w', encoding='utf-8') as testf:
             for tmpItem in  trainDataSet:
                 trainf.write(tmpItem)
             for testItem in  testDataSet:
                 testf.write(testItem)

使用和测试

使用面对对象编程思想写一下使用 网上的各种面向过程 看的眼花 本人有代码强迫症


这三个方法其它都可以使用  所以 面向过程
#去除 字母 和字符
def ClearTxt(raw):
    fil = re.compile(r"[^0-9a-zA-Z\u4e00-\u9fa5]+")
    return fil.sub(' ', raw)

#去除停顿词
def StopWords(stopPath= "./Data/stopwords.txt"):
    with open(stopPath, 'r', encoding='utf-8') as swf:
        return [line.strip() for line in swf]


#用结巴分词分割变成 闲暇 友人 光顾 这种形式
def SegSentence(sentence,stopWord):
    sentence =  ClearTxt(sentence)
    result= ' '.join([i for i in jieba.cut(sentence) if i.strip() and i not in stopWord])

    print("seg==",result)
    return  result

封装一下  面对对象编程
class  UsingText:
    """
        训练一个监督模型, 返回一个模型对象

        @param input:           训练数据文件路径
        @param lr:              学习率
        @param dim:             向量维度
        @param ws:              cbow模型时使用
        @param epoch:           次数
        @param minCount:        词频阈值, 小于该值在初始化时会过滤掉
        @param minCountLabel:   类别阈值,类别小于该值初始化时会过滤掉
        @param minn:            构造subword时最小char个数
        @param maxn:            构造subword时最大char个数
        @param neg:             负采样
        @param wordNgrams:      n-gram个数
        @param loss:            损失函数类型, softmax, ns: 负采样, hs: 分层softmax
        @param bucket:          词扩充大小, [A, B]: A语料中包含的词向量, B不在语料中的词向量
        @param thread:          线程个数, 每个线程处理输入数据的一段, 0号线程负责loss输出
        @param lrUpdateRate:    学习率更新
        @param t:               负采样阈值
        @param label:           类别前缀
        @param verbose:         ??
        @param pretrainedVectors: 预训练的词向量文件路径, 如果word出现在文件夹中初始化不再随机
        @return model object
    """
    def   __init__(self,inFilePath,dim=100,lr=0.1,epoch=5,loss="softmax",wordNgrams=2,prefixLabel="__label__"):
        self.ipt = inFilePath
        self.loss=loss
        self.wordNgrams= wordNgrams
        self.dim= dim
        self.lr= lr
        self.epoch= epoch
        self.modePath= f"dim{str(self.dim)}_lr{str(self.lr)}_iter{str(self)}.model"
        self.prefixLable= prefixLabel
    # 开始训练
    def Train(self):
        if os.path.exists(self.modePath):
             self.classify= fasttext.load_model(self.modePath)
        else:
            self.classify = fasttext.train_supervised(self.ipt,\
                                                      label=self.prefixLable,dim=self.dim,\
                                                      epoch=self.epoch,lr=self.lr,\
                                                      wordNgrams=self.wordNgrams)
            self.classify.save_model(self.modePath)
    def  Test(self,testFilePath):
         result = self.classify.test(testFilePath)

         print("result==",result)
    #计算精确度 召回率
    def CalPrecisionRecall(self,file='data_test.txt'):
        precision = defaultdict(int)
        recall = defaultdict(int)
        total = defaultdict(int)
        stopWord= StopWords()
        with open(file) as f:
            for line in f:
                label, content = line.split(',', 1)
                total[label.strip().strip(self.prefixLable)] += 1
                #labels2 = self.classify.predict([seg(sentence=content.strip(), sw='', apply=clean_txt)])

                contentList= [SegSentence(content.strip(),stopWord)]

                print("contentList==",contentList)

                labels2 = self.classify.predict(contentList)

                print("label2==",labels2)

                pre_label, sim = labels2[0][0][0], labels2[1][0][0]
                recall[pre_label.strip().strip(self.prefixLable)] += 1

                if label.strip() == pre_label.strip():
                    precision[label.strip().strip(self.prefixLable)] += 1

        print('precision', precision.keys())
        print('recall', recall.keys())
        print('total', total.keys())
        for sub in precision.keys():
            pre = precision[sub] / total[sub]
            rec = precision[sub] / recall[sub]
            F1 = (2 * pre * rec) / (pre + rec)
            print(f"{sub.strip(self.prefixLable)}  precision: {str(pre)}  recall: {str(rec)}  F1: {str(F1)}")



if __name__ == '__main__':

    #分割
    if(not os.path.exists("./Data/Out_Train.txt") or  not os.path.exists('./Data/Out_Test.txt') ):
        transData =  TransformData()

        transData.to_csv("./Data/data.txt","./Data/Out.csv")

        transData.SplitTrainTest("./Data/Out.csv")

    #训练
    useFast = UsingText("./Data/Out_Train.txt")
    useFast.Train()

    #useFast.Test("./Data/Out_Test.txt")
    
    #测试验证
    useFast.CalPrecisionRecall("./Data/Out_Test.txt")

    print("finish")

数据下载

链接: https://pan.baidu.com/s/13g8qi09NXafjJVZXWR2nVQ 密码: rsgl

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值