#物流快遞服務(wù)哪家強(qiáng)——基于Paddle的NLP對(duì)物流快遞的服務(wù)的分析(持續(xù)更新)

前言

首先聲明一下,這個(gè)是一個(gè)技術(shù)文章,中間可能會(huì)涉及到一些公司,名稱均已經(jīng)做脫敏處理,請(qǐng)勿對(duì)號(hào)入座。標(biāo)題純屬是做一下標(biāo)題黨,請(qǐng)勿當(dāng)真。

其次無論是基于什么的NLP,都會(huì)涉及到訓(xùn)練樣本的問題,由于服務(wù)的復(fù)雜性,樣本的分類可能會(huì)有所偏差,導(dǎo)致最終結(jié)果會(huì)有偏差,請(qǐng)大家理解,請(qǐng)勿當(dāng)真,僅當(dāng)作技術(shù)思路的參考。

背景

作為一個(gè)消費(fèi)者,我們常常可以看到各種數(shù)據(jù),例如經(jīng)常公開的一些行業(yè)數(shù)據(jù),XX快遞 X月的**萬票投訴率是多少,申訴率又是多少等等這些非常專業(yè)的數(shù)據(jù),這些數(shù)據(jù)都考慮了各家的業(yè)務(wù)量的大小了,非常科學(xué)。但是我們也知道譬如犯罪率,不能光看一個(gè)犯罪率數(shù)據(jù),還得多方面看,因?yàn)橐粋€(gè)盜竊和一個(gè)命案在犯罪率的統(tǒng)計(jì)上,都是一樣的,但是我們都知道這個(gè)背后的治安問題是不一樣嚴(yán)重的。同樣用投訴率等一樣會(huì)存在這個(gè)問題,我們不得不思考,在當(dāng)前機(jī)器學(xué)習(xí)已經(jīng)在大量應(yīng)用于各個(gè)行業(yè)的情況下,有沒有其他角度來看我們的快遞/物流服務(wù)?作為一個(gè)技術(shù)的愛好者,這里做一些拋磚引玉的做法,本文一共分兩個(gè)部分,第一個(gè)是利用機(jī)器學(xué)習(xí)進(jìn)行投訴分類,另外一個(gè)是利用機(jī)器學(xué)習(xí)進(jìn)行投訴的評(píng)價(jià),本文是利用機(jī)器學(xué)習(xí)進(jìn)行投訴分類供參考。也歡迎進(jìn)行技術(shù)討論。情感分類的后續(xù)我有空再放出來(解決前面說的用率值進(jìn)行統(tǒng)計(jì)的缺陷)。

說明

1、所有樣本來源sina黑貓投訴平臺(tái)的開放數(shù)據(jù),所以本文不會(huì)提供原始的數(shù)據(jù)供大家下載,如果有人需要復(fù)現(xiàn),請(qǐng)自己想辦法解決;

2、為了用于訓(xùn)練的樣本盡可能準(zhǔn)確,本文使用的樣本均是脫敏后,提供給不同的人,讓不同的人去分類,采用少數(shù)服從多數(shù)的分類原則最終確定樣本的分類;

3、由于服務(wù)的復(fù)雜性,一個(gè)投訴樣本里面,可能會(huì)存在多種分類可能,但是這里只采用一個(gè)分類,如:

**快遞送達(dá)快*驛站,快*驛站卻找理由不派送,每次都是同樣的理由,沒時(shí)間只能自取,不送貨,態(tài)度特別不好,沒有經(jīng)過同意直接放驛站,給*通本地網(wǎng)點(diǎn)打電話,一直說他們聯(lián)系快*驛站,結(jié)果聯(lián)系了幾天還是不派送,聯(lián)系*通在線客服投訴,在線客服卻不登記,不授予投訴。本人收件地址已經(jīng)備注,不要放驛站。

這個(gè)投訴內(nèi)容分類,分類是“未經(jīng)允許放驛站”?“不送貨上門”?“服務(wù)態(tài)度”?都有可能,不同的人可能有不同的意見,這里采用一個(gè)投訴只能有一個(gè)分類,然后多人進(jìn)行這個(gè)樣本進(jìn)行標(biāo)記分類,最后服從多數(shù)人的分類來確定最后的分類。

4、由于數(shù)據(jù)是來源于互聯(lián)網(wǎng)的平臺(tái)的數(shù)據(jù),而數(shù)據(jù)是消費(fèi)者自己輸入的,可能會(huì)一面之詞的情況,不代表任何立場,僅用于學(xué)術(shù)討論。

運(yùn)行環(huán)境

1、操作系統(tǒng) Ubuntu20.4
2、Python3.9
3、paddle2.1
4、Tesla K20(之前的GPU計(jì)算卡被燒了,現(xiàn)在礦工把計(jì)算卡都炒上天了,木有錢買新卡,只能把N年前退役的K20拿出來用)

各位看官覺得有用的話,可以打賞下買個(gè)新的計(jì)算卡

整體思路

image.png

如圖示,獲取到數(shù)據(jù)后,抽取一部分出來作為樣本,進(jìn)行打標(biāo),然后對(duì)模型進(jìn)行訓(xùn)練,用訓(xùn)練后的模型對(duì)未打標(biāo)分類的投訴數(shù)據(jù)進(jìn)行預(yù)測,預(yù)測結(jié)果作為分類結(jié)果,再用結(jié)果進(jìn)行分析。

注意事項(xiàng)

1、樣本的平衡性,由于采用機(jī)器學(xué)習(xí),所以對(duì)于不同分類的樣本數(shù)據(jù),大家要進(jìn)行合理的控制,如果樣本不均衡,可能會(huì)導(dǎo)致結(jié)果的失真。這是和機(jī)器學(xué)習(xí)的特效是有關(guān)的,舉個(gè)例子來說:

如果100個(gè)樣本里面,有99個(gè)男人,1個(gè)是女人,那么最后訓(xùn)練出來的模型盡管看起來ACC非常高,但是實(shí)際可能不如人意。因?yàn)殡S便抽一個(gè)出來,預(yù)測是男人的準(zhǔn)確率都可以到99%,所以無論是訓(xùn)練的樣本還是驗(yàn)證的樣本,我們都應(yīng)該盡可能的平衡,每個(gè)分類都是差不多的數(shù)量的樣本。

2、分詞過程中無意義的詞匯的過濾。投訴的原始數(shù)據(jù)中,有很多客戶的描述得非常詳盡,但是對(duì)于我們的機(jī)器學(xué)習(xí)來說,有時(shí)反而是一種阻礙,例如:

假如樣本數(shù)據(jù)中,劉1刀~劉100刀是冠軍,王1刀~王100刀是亞軍,那么很有可能給一個(gè)叫王*刀的給他預(yù)測,預(yù)測結(jié)果就是亞軍,但是我們知道這個(gè)預(yù)測并不科學(xué),但是在機(jī)器學(xué)習(xí)中,他們洞察出來的結(jié)果就是王*刀,是亞軍的概率是99%以上??

在開始動(dòng)手?jǐn)]代碼前,先看一下結(jié)果


image.png

從這里看,模型的分類區(qū)分度還是不錯(cuò)的
今天先寫到這里,要準(zhǔn)備回家做飯了,如果大家想看,記得點(diǎn)贊+收藏,點(diǎn)贊越多,我更新動(dòng)力越足。
———————————————————————————————————————
接著更新:
下面我們正式開始看看怎樣做吧。

Setp1:分類標(biāo)準(zhǔn)

在開始學(xué)習(xí)前,我們先確定標(biāo)準(zhǔn)分類,這里我們一共分10類(這個(gè)分類或許有不合理的地方,但是大家當(dāng)作技術(shù)研究探討使用就好,因?yàn)榉诸悰]有絕對(duì)的標(biāo)準(zhǔn),例如很多信息不更新,其實(shí)是由于貨物丟(或者是虛假丟貨)了,但是這個(gè)事情我們不能確定,而客戶投訴內(nèi)容只是說貨物中途幾天不動(dòng),我們只能歸類為信息更新不及時(shí)),分別為:

破損丟失
信息不更新
虛假簽收
未經(jīng)允許放驛站
其他
亂收費(fèi)
派送不上門
不上門取件
時(shí)效
虛假物流信息
服務(wù)態(tài)度

Setp2:樣本打標(biāo)

前面提到,我們打標(biāo)是一個(gè)非常關(guān)鍵的事情,我們機(jī)器學(xué)習(xí)就譬如是教會(huì)小朋友明辨是非,而樣本則是我們的教材,如果我們的教材出問題了,教學(xué)的結(jié)果可能就是錯(cuò)誤的。這里為了追求盡可能的相對(duì)科學(xué),我們把數(shù)據(jù)脫敏后,多人進(jìn)行標(biāo)記,然后采用投票的原則,投出最后的分類。


image.png

例如,上面的例子,分別給3個(gè)人進(jìn)行打標(biāo),其中2個(gè)分類為信息不更新,1個(gè)人分類為時(shí)效問題,這里我們根據(jù)最后分類結(jié)果投票的結(jié)果,選用分類為信息不更新,盡管說分類為時(shí)效也是有一定的道理的,但是無論如何我們都需要確定下來一個(gè)唯一的分類(突然讓我想起瘋?cè)墓适??……正常的反而被認(rèn)為是瘋的,但是這就是機(jī)器學(xué)習(xí)……??)。

Setp3:數(shù)據(jù)準(zhǔn)備

獲取到的數(shù)據(jù)比較多,我們不可能對(duì)所有的投訴都進(jìn)行人工分類,這也違背了我們這期的目的,我們對(duì)一些數(shù)據(jù)進(jìn)行打標(biāo)后,每個(gè)分類抽取100個(gè)樣本,然后按照下面的格式生成一個(gè)txt文件

投訴內(nèi)容_!_分類

這里需要注意,這里我用的分割符號(hào)是_ ! _,并不是",",因?yàn)槿绻闷渌?hào),很容易和投訴內(nèi)容中的符號(hào)重疊,導(dǎo)致分割不準(zhǔn)確,所以這里用了組合符合來做分割符,當(dāng)然,你也可以按照你的習(xí)慣來,不過建議是多個(gè)符號(hào)組合的分割符號(hào)。
由于機(jī)器學(xué)習(xí)不能直接對(duì)中文進(jìn)行學(xué)習(xí),我們需要將中文進(jìn)行轉(zhuǎn)換成為編碼

#coding=utf-8
'''
生成字典,如果沒有特殊情況,可以使用默認(rèn)字典就好,如果需要優(yōu)化,可以使用默認(rèn)字典+分詞字典
'''
import os
import io
import utils.jiebainfer as jiebainfer
import utils.myfile as myfile

data_root_path = './dataset'
data_path = os.path.join(data_root_path, 'list.txt')

def create_dict(data_path, data_root_path):
    print('準(zhǔn)備生成字典')
    dict_set = set()
    dict_words_set = set()
    type_dict=set()
    with io.open(data_path, 'r', encoding='utf-8') as f:
        lines = f.readlines()
        print(lines)
    stopwords=myfile.Readstopword(os.path.join(data_root_path, 'stop_words.txt'))
    for line in lines:
        title = line.split('_!_')[0].replace('\n', '')
        for s in title:
            dict_set.add(s)
        strlist=jiebainfer.split(title)
        for word in strlist:
            content_str = ''
            for i in word:
                if myfile.is_chinese(i):
                    content_str = content_str+i
            if word in stopwords:
                print(content_str+'是停用詞')
            else:
                dict_words_set.add(content_str)
        type = line.split('_!_')[-1].replace('\n', '')
        type_dict.add(type)
    dict_make(data_root_path,'character_dict.txt', dict_set)
    dict_make(data_root_path,'word_dict.txt', dict_words_set)
    dict_make(data_root_path,'type_dict.txt', type_dict)

    print("數(shù)據(jù)字典生成完成!")


def dict_make(dict_path,name, dict_set):
    dict_path = os.path.join(dict_path, name)
    dict_list = []
    i = 0
    for s in dict_set:
        dict_list.append([s, i])
        i += 1
    dict_txt = dict(dict_list)
    end_dict = {"<unk>": i}
    dict_txt.update(end_dict)
    with io.open(dict_path, 'w', encoding='utf-8') as f:
        f.write(str(dict_txt))

if __name__ == '__main__':
    create_dict(data_path, data_root_path)

我們把樣本txt文件放到

./dataset/list.txt

運(yùn)行上面的python,則可以生成單個(gè)字的詞典和用結(jié)巴分詞的詞典,這里需要注意的是,用分詞詞典,詞典會(huì)比較大,因?yàn)橹袊臐h字就那么幾千個(gè),但是組成的詞卻是可以很多的,但是正是由于這樣,用分詞的詞典的準(zhǔn)確度會(huì)高于單字作為詞典的(樣本足夠的情況下)。(今天先寫這里,待續(xù)……)
————————————————————————————————————
完成字典工作后,我們需要把前的樣本分為訓(xùn)練樣本和驗(yàn)證訓(xùn)練效果的兩組樣本,這里我們驗(yàn)證按照20%的比例從總樣本集中抽取,并且為了得到先對(duì)比較客觀的準(zhǔn)確率數(shù)據(jù),我們的驗(yàn)證樣本不和訓(xùn)練樣本重復(fù)(其實(shí)在學(xué)習(xí)樣本不多的情況下,這兩個(gè)樣本是可以重疊,但是這樣會(huì)導(dǎo)致訓(xùn)練過程中看到的準(zhǔn)確率偏高,但是由于訓(xùn)練樣本增多了,其實(shí)效果會(huì)更加好,但是實(shí)際沒有看到的數(shù)據(jù)高)

#coding=utf-8

'''
讀取詞典和分類詞典,將文本轉(zhuǎn)化為訓(xùn)練和驗(yàn)證的數(shù)據(jù)
'''
import os
import io
import utils.jiebainfer as jiebainfer
import utils.myfile as myfile

data_root_path='./dataset'

def create_data_list(dir):
    # 清空歷史數(shù)據(jù)
    with io.open(dir + 'test_list.txt', 'w') as f:
        pass
    with io.open(dir + 'train_list.txt', 'w') as f:
        pass
    with io.open(data_root_path + 'error.txt', 'w') as f:
        pass

    with io.open(os.path.join(data_root_path, 'word_dict.txt'), 'r', encoding='utf-8') as f_data:
        dict_txt = eval(f_data.readlines()[0])
        print('字典長度{}'.format(len(dict_txt.keys())))
        print('字典最大序列{}'.format(len(dict_txt.keys())-1))

    with io.open(os.path.join(data_root_path, 'type_dict.txt'), 'r', encoding='utf-8') as f_data:
        type_txt = eval(f_data.readlines()[0])
        print('分類字典長度{}'.format(len(type_txt.keys())))
        print('分類字典最大序列{}'.format(len(type_txt.keys())-1))

    with io.open(os.path.join(dir, 'list.txt'), 'r', encoding='utf-8') as f_data:
        lines = f_data.readlines()
    i = 0
    errorstrlist=[]
    for line in lines:
        title = line.split('_!_')[0].replace('\n', '')
        l = line.split('_!_')[1]
        print(l,title)
        # 對(duì)title分詞
        words_list=jiebainfer.split(title)
        if i % 5 == 0:
            makelistfile(dir,'test_list.txt',words_list,dict_txt,errorstrlist,type_txt,l)
        else:
            makelistfile(dir,'train_list.txt',words_list,dict_txt,errorstrlist,type_txt,l)
        i += 1

    # 無法編碼的字符記錄下來
    errorrec(errorstrlist)
    # 保存新的詞典
    savedict(dict_txt)
    print("數(shù)據(jù)列表生成完成!")

def makelistfile(dir,filename,words_list,dict_txt,errorstrlist,type_txt,l):
    # 讀取停用詞
    stopwords=myfile.Readstopword(os.path.join(data_root_path, 'stop_words.txt'))
    labs = ""
    with io.open(os.path.join(dir, filename), 'a', encoding='utf-8') as f_train:
        for s in words_list:
            # 只保留中文
            content_str = ''
            for k in s:
                if myfile.is_chinese(k):
                    content_str = content_str+k
            # 判斷是否是停用詞
            if content_str in stopwords:
                print(content_str+'是停用詞')
            else:
                try:
                    lab = str(dict_txt[content_str])
                except:
                            # lab = str(dict_txt['<unk>'])
                    if not content_str in errorstrlist:
                        errorstrlist.append(content_str)
                            # 動(dòng)態(tài)增加到詞典
                    dict_txt[content_str]=len(dict_txt.keys())
                    lab = str(dict_txt[content_str])
                labs = labs + lab + ','
        labs = labs[:-1]
        ln=str(type_txt[l.replace('\n','')])
        labs = labs + '\t' + ln + '\n'
        size=labs.split(',')
        if  len(size)>0 and len(l)>0:
            f_train.write(labs)
        else:
            print('特征不夠,拋棄')

def savedict(dict):
    '''
    保存新的詞典
    '''
    with io.open(data_root_path + 'newdict.txt', 'w') as f:
        f.write(str(dict))
        f.close()

def errorrec(strlist):
    '''
    編碼過程中遇到生僻字,無法編碼,記錄一下,方便優(yōu)化字典
    '''
    with io.open(data_root_path + 'error.txt', 'a') as f:
        for string in strlist:
            f.write(string)
        f.close()

if __name__ == '__main__':
    create_data_list(data_root_path)

在這里,我們還把動(dòng)態(tài)擴(kuò)充詞典的功能加上了,后面如果需要增加樣本,而之前的分詞詞典沒有的,會(huì)動(dòng)態(tài)增加到新的詞典中,這樣可以使的詞典進(jìn)行動(dòng)態(tài)的變化(如果使用單字詞典,建議使用網(wǎng)上的漢字字典,基本上不用再次動(dòng)態(tài)擴(kuò)充)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,687評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,682評(píng)論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,011評(píng)論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評(píng)論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,183評(píng)論 0 290
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,714評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,435評(píng)論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,665評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,838評(píng)論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評(píng)論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,379評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,627評(píng)論 2 380

推薦閱讀更多精彩內(nèi)容