手段非常拙劣的自然語言處理

本文簡述實(shí)現(xiàn)自然語言處理中最基本需求的幾個笨辦法忆植,也是最初引發(fā)思考的要點(diǎn)放可。文章不涉及專業(yè)的先進(jìn)的系統(tǒng)化的自然語言處理方案,只是一篇散文朝刊。沒錯我就是標(biāo)題黨耀里。


事情緣起于,我在做用戶反饋的時候要對成百上千條用戶留言進(jìn)行貼標(biāo)簽的工作拾氓,也就是根據(jù)其反饋內(nèi)容和重要程度來分類冯挎,把要解決的緊急問題反饋給工程師,建設(shè)性意見提交給產(chǎn)品部門痪枫,好評作為打廣告的素材等等织堂。懶惰的本性告訴我人肉分類不是辦法,要訴諸更為高效的自動化手段奶陈。所以開始走進(jìn)自然語言處理的坑易阳。

我知道要做好這個,除了在語言學(xué)上了解句法詞法吃粒,想要獲得好的效果需要使用先進(jìn)復(fù)雜的機(jī)器學(xué)習(xí)算法潦俺,來使得變化復(fù)雜多樣的句子可以被程序“理解”。關(guān)于這些內(nèi)容徐勃,有一本專門從實(shí)踐角度介紹自然語言處理的書非常對口事示,叫做《Natural Language Processing with Python》,質(zhì)量上乘僻肖,值得深入學(xué)習(xí)肖爵。

但是考慮到我沒有大把時間和能力去深入理解復(fù)雜的算法和工具,我必須盡快在效率上給出看得見的改進(jìn)臀脏,所以我開始自己思考如何解決這樣的問題劝堪。

關(guān)鍵詞過濾

因?yàn)橛脩艚o出的反饋不是天馬行空的冀自,關(guān)于產(chǎn)品內(nèi)容有非常高的針對性,所以這套識別方法不需要具有普適性秒啦,只要能把這類特定內(nèi)容的文本做出劃分即可熬粗。

觀察發(fā)現(xiàn)在“手機(jī)空間不夠”這類反饋中大量出現(xiàn)關(guān)鍵詞 storagefull余境、room驻呐、spacememory 等芳来,這類詞具有兩種特點(diǎn):其一含末,具有高度的指向性,即在手機(jī) App 反饋這個大語境下绣张,這類詞所指的意思是精準(zhǔn)而沒有歧義的答渔;其二,在其他反饋中很少見到這類詞的使用侥涵。具有同樣特點(diǎn)的還有分類“三俗內(nèi)容”下的關(guān)鍵詞 porn沼撕、nakedbitch芜飘、xvideos务豺、fuckinappropriate 等嗦明;在分類“費(fèi)電
中有關(guān)鍵詞 power笼沥、battery 等;在分類“標(biāo)題黨和假新聞”中有關(guān)鍵詞 fake娶牌、inaccurate奔浅、irrelevant 等。這些適用范圍狹小而指代明確的關(guān)鍵詞诗良,在絕大多數(shù)情況下是足以作為定性依據(jù)的特征詞汹桦,所以使用關(guān)鍵詞查找來處理這些分類是比較靠譜的選擇。

所以這個方法的思路就是鉴裹,便利反饋中的所有詞舞骆,當(dāng)與預(yù)先設(shè)定的關(guān)鍵詞列表相匹配時,增加這一分類的得分径荔,最后比較不同分類得分的大小督禽,取最高值(也就是匹配關(guān)鍵詞數(shù)量最多)的分類作為整個反饋的分類。

如下定義每個分類的關(guān)鍵詞总处,以及所有采用關(guān)鍵詞過濾方法的分類的集合狈惫。

# Python Code
# Filename: Config.py

Map = {
    '三俗內(nèi)容': 'KW_SanSuNeiRong',
    '標(biāo)題黨和假新聞': 'KW_BiaoTiDangHeJiaXinWen',
    '手機(jī)空間不夠': 'KW_ShouJiKongJianBuGou',
    '費(fèi)電': 'KW_FeiDian'
}

# 三俗內(nèi)容
KW_SanSuNeiRong = [
    'naked',
    'porn',
    'inappropriate',
    'bitch',
    'whore',
    'unduly',
    'xvideo',
    'xvideos'
]

# 標(biāo)題黨和假新聞
KW_BiaoTiDangHeJiaXinWen = [
    'fake',
    'inaccurate',
    'irrelevant',
    'accurate'
]

# 手機(jī)空間不夠
KW_ShouJiKongJianBuGou = [
    'storage',
    'space',
    'memory',
    'room',
    'full'
]

# 費(fèi)電
KW_FeiDian = [
    'power',
    'consumptiion',
    'battery'
]

分析關(guān)鍵詞時,按照分類和關(guān)鍵詞得分建立字典鹦马,最后按照得分最大的分類作為結(jié)果虱岂,當(dāng)有多個得分相同的分類時玖院,由于循環(huán)結(jié)構(gòu)的特性菠红,將按照分類在 Map 中被定義的順序進(jìn)行取舍第岖,所以 Map 也暗含了一個優(yōu)先級的意思。

# Python Code
# Filename: Program.py

import Config

# words is a list of single word of lower case, preprocessed when reading files.
# example: ['my', 'phone', 'is', 'low', 'on', 'memory']

def analyzeKeyword(words):
    chart = {}
    for genre in Map:
        score = analyzeFrequency(words, Map[genre])
        chart[genre] = score
    return getHighestScoreGenre(chart)

def analyzeFrequency(words, map)
    score = 0
    keywords = getattr(Config, map)
    for kw in keywords:
        for word in words:
            if kw == word:
                score += 1
    return score

def getHighestScoreGenre(dict)
    max = 0
    result = "Unknown"

    genres = [g for g in dict]
    genres.reverse()

    for genre in genres:
        if dict[genre] >= max:
            max = dict[genre]
            result = genre

    return result

res = analyzeKeyword(['my', 'phone', 'is', 'low', 'on', 'memory'])
print(res)

# Output: 手機(jī)空間不夠

上例中试溯,因?yàn)殛P(guān)鍵詞 memory 的匹配蔑滓,分類 手機(jī)空間不夠 的得分為 1,其余分類都是 0遇绞,故最終分類被定位 手機(jī)空間不夠键袱。

幾個小技巧:

  • 將分類和關(guān)鍵詞列表單獨(dú)寫在文件 Config.py 中,方便之后將新的關(guān)鍵詞添加至分析列表中摹闽。
  • 使用 getattr 函數(shù)蹄咖,利用反射的方法動態(tài)獲取 Config 中的列表,增加擴(kuò)展性付鹿。
  • genres.reverse() 是為了反向遍歷 Map 字典澜汤,如此當(dāng)“新值大于等于舊值”就更新最大值時,實(shí)際上實(shí)現(xiàn)了“排在上面的分類比排在下面的分類具有更高優(yōu)先級”的邏輯舵匾,使得當(dāng)兩個多個分類得分相同時俊抵,總按照最上面的分類定性。

簡單的情感分析

關(guān)鍵詞過濾針對使用寬泛的形容詞束手無策坐梯,比如認(rèn)為 good 代表好評徽诲,那么前置一個否定詞 not 的話,整句意思完全相反吵血,同理 not bad 表示還不錯谎替。所以我進(jìn)一步研究了簡單的情感判斷。

思路是:前置否定詞(可有可無) + 后置形容詞 = 一個組蹋辅,否定詞負(fù)負(fù)得正钱贯,結(jié)合最后的形容詞是褒義還是貶義來定性這個組到底是好評還是差評。一個用戶反饋中以句子為單位晕翠,每個句子統(tǒng)計好評組和差評組的個數(shù)喷舀,數(shù)量多的作為句子的特性,所有句子特性采用同樣的標(biāo)準(zhǔn)組合起來淋肾,作為整個反饋的情感特性硫麻。

首先還是建立詞庫。

# Python Code
# Filename: Config.py

ST_Negative = [
    "not",
    "donot",
    "don't",
    "dont",
    "doesnot",
    "doesn't",
    "doesnt",
    "isnot",
    "isn't",
    "isnt",
    "ain't",
    "cannot",
    "can't",
    "cant",
    "couldnot",
    "couldn't",
    "couldnt",
    "never",
    "didnot",
    "didn't",
    "didnt"
]

ST_Good = [
    'good',
    'great',
    'awesome',
    'amazing',
    'wonderful',
    'fabulous',
    'cool',
    'like',
    'love',
    'interesting',
    'interested',
    'use'
]

ST_Bad = [
    'bad',
    'useless',
    'boring',
    'junk',
    'rubbish',
    'nonsense',
    'dumb',
    'hate',
    'stupid',
    'suck',
    'sucks',
    'fuck',
    'shitty'
]

接下來是主程序樊卓。

# Python Code
# Filename: Program.py

import Config

# sentences is a list of sentences of lower-case character preprocessed when reading files.
# example: ['it's not bad', 'and really good and shitty']

def analyzeSentence(sentences)
    score = 0
    for sentence in sentences:
        tmp = analyzeSentenceScore(sentence)
        score += tmp
    return 'Good' if score > 0 else ('Bad' if score < 0 else 'Unknown')

def analyzeSentenceScore(sentence):
    words = [w for w in text.split(' ') if w != ' ']
    isnegative = 0

    good_score = 0
    bad_score = 0

    for word in words:
        # Check negative.
        negative = 1 if word in Config.ST_Negative else 0
        isnegative = 1 if negative == 1 else isnegative

        # Check sentiment.
        good = 1 if word in Config.ST_Good else 0
        bad = 1 if word in Config.ST_Bad else 0
        sentiment = 1 if good > bad else (0 if good < bad else -1)

        # Score.
        if sentiment != -1:
            good_score += 1 if ((not isnegative) and sentiment) or (isnegative and (not sentiment)) else 0
            bad_score += 0 if ((not isnegative) and sentiment) or (isnegative and (not sentiment)) else 1
            isnegative = 0

    # Return logic.
    result = 1 if good_score > bad_score else (-1 if bad_score > good_score else 0)
    return result

res = analyzeSentence(['it's not bad', 'and really good and shitty'])
print(res)

# Output: Good

上例中拿愧,第一句定性為 Good,得分 1碌尔,第二句存在一個 Good 和一個 Bad浇辜,故無法判斷券敌,得分 0,總分 1柳洋,為正待诅,故整個反饋判定為 Good

幾個小技巧:

  • Python 的三元運(yùn)算符 <TrueValue> if <Expression> else <FalseValue> 非常好用熊镣,能極大地節(jié)約寫作空間卑雁,在合適的嵌套下可以將比較復(fù)雜的思路簡單地表示出來。
  • 每一個詞只可能是 好評詞绪囱、差評詞無關(guān)詞 中的一種测蹲,前兩者作為 形容詞,所以當(dāng) sentiment == -1 時鬼吵,實(shí)際上表示這個詞是無關(guān)詞扣甲,那么需要繼續(xù)向后尋找形容詞,所以“一組”的概念沒有結(jié)束齿椅。
  • 當(dāng)出現(xiàn)一個 形容詞 的時候琉挖,意味著“一組”結(jié)束了,所以重置標(biāo)記變量 isnegative = 0媒咳,表示“默認(rèn)情況下粹排,在檢測到否定詞之前,都認(rèn)為是沒有否定詞”涩澡。
  • 關(guān)鍵的邏輯判斷顽耳,可以翻譯如下:對于當(dāng)前一個組來說,整個句子的好評得分 += 1 如果(沒有否定詞妙同,并且是好評射富;或者有否定詞,并且是差評)粥帚,否則 0胰耗。差評得分同理。說白了就是芒涡,“very good” 加一分柴灯,“not bad” 加一分;“very bad” 減一分费尽,“not good” 減一分赠群。
  • 最后比較整個句子多個組的好評得分和差評得分,來確定整句話的特性旱幼。

整合與總結(jié)

因?yàn)榍楦信袛嗟倪壿嫺鼜?fù)雜查描,且穩(wěn)健性更低,所以將二者結(jié)合使用。當(dāng)關(guān)鍵詞出現(xiàn)無法判斷的情況時冬三,使用情感判斷匀油,給出一個大概的方向。當(dāng)情感判斷也無法給出結(jié)論時勾笆,判定為最終無法判斷敌蚜。

實(shí)測表明,這套方法在訓(xùn)練集上有 55% 的準(zhǔn)確度匠襟,在兩個全新的測試集上分別有 37% 和 43% 左右的準(zhǔn)確度钝侠。說實(shí)話我已經(jīng)很欣慰了,如此簡陋的方法竟然可以省掉平均 40%+ 的人力酸舍,π_π……

扣題,所謂“拙劣”的方法里初,是因?yàn)檫@里除了思想還有點(diǎn)東西以外啃勉,在純統(tǒng)計分析技術(shù)上幾乎沒有任何深度可言,代碼寫的也是大白話双妨。核心功能十分有限淮阐,解決不了單詞拼寫錯誤,一詞多義和復(fù)雜句前后邏輯識別等更深奧的問題刁品。在最終的實(shí)現(xiàn)里泣特,定義了 ReviewSentence 兩個類,來實(shí)現(xiàn)更簡明清晰的封裝挑随,在程序結(jié)構(gòu)上看著還不錯状您。另外,上一段借用了機(jī)器學(xué)習(xí)中的概念兜挨,也是強(qiáng)行打腫臉充胖子了膏孟。

自然語言處理是一個長久又新潮的問題,專業(yè)的處理方法可以使用 NLTK 包等拌汇,用更高級的機(jī)器學(xué)習(xí)和文本挖掘的方法去處理更復(fù)雜的句子柒桑。我呢,學(xué)不來那些高深的東西噪舀,只能在能力所及之內(nèi)把有限的思考投入到無限的嘗試中魁淳,解決一點(diǎn)算一點(diǎn)。但是在這個過程中我體會得到這些高級方法誕生伊始時的一些問題与倡,以及想要解決它們所引發(fā)的一些思考界逛。比如為什么會使用向量的運(yùn)算,實(shí)際上就是對具有多個分類得分的句子之間的相似性蒸走,關(guān)聯(lián)性進(jìn)行計算仇奶,因?yàn)槊總€分類方向都是一個得分,所以可以看做一個向量;而語義理解上该溯,根據(jù)詞法語法和慣用句式來分析一句話岛抄,采用不同的提取方法獲得特征值,也是常見的手段狈茉。

之前文章里提到的大神同學(xué)夫椭,最近在深入學(xué)習(xí)機(jī)器學(xué)習(xí)和文本挖掘的理論,看他寫的東西檔次就是不一樣氯庆,起點(diǎn)比我高多了蹭秋,相比之下我真是土鱉一只……接下來有時間的話我會繼續(xù)看前文提到的那本書(畢竟現(xiàn)在才看到第二章),然后搞一點(diǎn)高端的方法吧堤撵。


哈哈仁讨,哈哈哈哈哈……自娛自樂中~~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市实昨,隨后出現(xiàn)的幾起案子洞豁,更是在濱河造成了極大的恐慌,老刑警劉巖荒给,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丈挟,死亡現(xiàn)場離奇詭異,居然都是意外死亡志电,警方通過查閱死者的電腦和手機(jī)曙咽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來挑辆,“玉大人例朱,你說我怎么就攤上這事≈Γ” “怎么了茉继?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蚀乔。 經(jīng)常有香客問我烁竭,道長,這世上最難降的妖魔是什么吉挣? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任派撕,我火速辦了婚禮,結(jié)果婚禮上睬魂,老公的妹妹穿的比我還像新娘终吼。我一直安慰自己,他們只是感情好氯哮,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布际跪。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪姆打。 梳的紋絲不亂的頭發(fā)上良姆,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天,我揣著相機(jī)與錄音幔戏,去河邊找鬼玛追。 笑死,一個胖子當(dāng)著我的面吹牛闲延,可吹牛的內(nèi)容都是我干的痊剖。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼垒玲,長吁一口氣:“原來是場噩夢啊……” “哼陆馁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起侍匙,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤氮惯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后想暗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡帘不,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年说莫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寞焙。...
    茶點(diǎn)故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡储狭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出捣郊,到底是詐尸還是另有隱情辽狈,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布呛牲,位于F島的核電站刮萌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏娘扩。R本人自食惡果不足惜着茸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望琐旁。 院中可真熱鬧涮阔,春花似錦、人聲如沸灰殴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至伟阔,卻和暖如春辣之,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背减俏。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工召烂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人娃承。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓奏夫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親历筝。 傳聞我的和親對象是個殘疾皇子酗昼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評論 2 349

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

  • 命名實(shí)體識別 命名實(shí)體的提出源自信息抽取問題,即從報章等非結(jié)構(gòu)化文本中抽取關(guān)于公司活動和國防相關(guān)活動的結(jié)構(gòu)化信息梳猪,...
    我偏笑_NSNirvana閱讀 10,219評論 1 35
  • 烏鎮(zhèn)/小甘 月華波動麻削,時光逗留 在這曼妙的一刻 我要去尋枕上江南的烏鎮(zhèn) 初見時驚艷,離別后...
    小甘最好閱讀 253評論 0 2
  • 混混沌沌的活著 每天吃飯睡覺解決生理問題 濟(jì)南的霧霾天很多過了夏天就是冬天 陽光好的時候我就去曬曬 把自己像被子一...
    李小歪閱讀 357評論 0 2
  • 翻開父親的遺物春弥,點(diǎn)點(diǎn)滴滴都是回憶呛哟。 龍亭湖邊的開封市圖書館,每周周末雷打不動的匿沛,爸爸都會送我去看書借書扫责,從6歲到1...
    清空_7467閱讀 395評論 6 2
  • 晚風(fēng)涼,落雨依晰 殘雨獨(dú)逃呼,頻頻思量深幾許 寒水葉絡(luò)深沉意 無言處鳖孤,臥聽風(fēng)雨 思起尚人昔
    冰公寒塵閱讀 402評論 5 8