NLP 系列之一:用 Trigram 进行 Article Spinner

Article Spinner 指文章的制作者通过改写文章的部分段落,或者用相似内容替换文中词汇,句子甚至段落来批量制造内容相近文章的技术。Article Spinner 主要运用在Search Engine Optimization(SEO)中,可以在批量生成近似内容的同时,有效降低文章的相似度来避开搜索引擎对重复内容的惩罚。换句话说,有了这个方法,站长再也不用为了SEO把一个关键词用看不见的颜色重复一万次了。

本文接下来的内容主要分为三个部分,第一部分是简单介绍 Article Spinner 中最常用的三连词(trigram)方法的思路,第二部分是介绍三连词方法的步骤,最后一部分是介绍三连词方法的 Python 实现。


Article Spinner 中最常用的技术就是对文中的词汇进行近义词替换,替换的依据有很多,在这里介绍一下利用三连词(trigram)的方法。

三连词是上下文(context)的最简化形式。在Article Spinner 问题中,我们用词语的条件概率来表示上下文。首先将所有出现的词语分别标记为w(1),w(2)...w(n),然后求出P(w(i)|w(1),w(2),..w(i-1),w(i+1),..w(n))。在三连词中,这个条件概率被进一步简化为P(w(i)|w(i-1),w(i+1)),即一个词在一对特定的词之间出现的概率。随后,在出现该特定的两个词时,程序会选择若干条件概率较大的w(i)之一,对原本夹在中间的词进行替换。在实际应用中,不会将每个词都替换掉,而是设置阈值来控制替换控制的比例,因为如果替换过多,可能会生成的内容不合语法或者有歧义。


接下来简单描述一下使用三连词进行 Article Spinner 的流程。

首先,对原始文章进行分词处理。

第二步,建立一个三连词的字典dictionary_w,以文中所有(上一个词,下一个词)的组合作为key,将文中所有以(上一个词,word,下一个词)形式出现过的word放入一个list,作为对应的value。

第三步,基于第二步的dictionary_w,建立关于三连词概率的字典dictionary_p,key与dicionary_w相同,value为dictionary_w里对应value的每个词出现的频率。这个频率将被作为概率的估计,在下一步作为词语替换的依据。

最后一步,进行替换,设定一个阈值,对文中所有词按阈值的比例进行替换。替换的基本规则为选择上下文三连词中条件概率较大的词语,为了避免同一个同一个上下文词组总是被固定的中间词替换,通常还会加入一些随机性,来保证替换词语的多样性。


最后来看一下用三连词进行 Article Spinner 的 Python 实现。本文使用的例子是亚马逊的评论内容。

import nltk
import numpy as np
import random
from bs4 import BeautifulSoup 

导入数据。

positive_reviews = BeautifulSoup(open('positive.review', encoding='utf-8' ).read())
positive_reviews = positive_reviews.findAll('review_text')

建立三连词的字典trigram。

trigrams = {}
for review in positive_reviews:
    s = review.text.lower()
    tokens = nltk.tokenize.word_tokenize(s)
    for i in range(len(tokens)-2):
        k = (tokens[i],tokens[i+2])
        if k not in trigrams:
            trigrams[k] = []
        trigrams[k].append(tokens[i+1])

建立三连词概率的字典trigrams_p。

trigrams_p = {}
for k,word in trigrams.items():
    if(len(set(word))>1):
        d = {}
        n = 0
        for w in word:
            if w not in d:
                d[w] = 0
            d[w] += 1
            n += 1
        for w,c in d.items():
            d[w] = float(c)/n
        trigrams_p[k] = d

定义随机抽取的函数。

def random_choice(d):
    r = random.random()
    cum = 0
    for k,c in d.items():
        cum += c
        if r < cum:
            return k

对全文进行词语替换,在这里设置的阈值是第八行的0.2 。

def test_spinner():
    review = random.choice(positive_reviews)
    s = review.text.lower()
    print("original:")
    print(s)
    tokens = nltk.tokenize.word_tokenize(s)
    for i in range(len(tokens)-2):
        if random.random() < 0.2:
            k = (tokens[i],tokens[i+2])
            if k in trigrams_p:
                word = random_choice(trigrams_p[k])
                tokens[i+1] = word
    
    print("spun:")
    print(" ".join(tokens))

最后运行test_spinner()函数即可。会打印出原始的评论文本和生成的替换文本。

test_spinner()

将生成的一组文本附在下面,供大家参考。

original:

this product was perfect. it's a sturdy case that holds my large collection of cd's and dvd's.
my other cases were flimsy and wore out fast. this one has a hard outside shell and the inside holds my dvd's nicely.
so i have no complaints. and at the price i paid i'd say this was a great deal

spun:
this phone was perfect . it 's a great case that holds my large collection of cd 's and dvd 's . my other cases were flimsy and wore out fast . this card has a hard outside shell . the inside holds my dvd 's nicely . so i have no complaints . and at the price i paid i 'd say this was a great deal
Comments
Write a Comment