回忆上篇,咱们详细介绍了怎么完成猫途鹰网站的中英文谈论数据采集、入库和整理。本篇中,咱们会重点介绍数据建模的原理和代码完成,其间包括 emoji 剖析、情感剖析、分词、词性词频剖析、关键词剖析、词云和主题模型文本分类。

数据建模

在这个过程中,咱们将对语料数据进行针对性处理,使这类数据在剖析中发挥它的价值。咱们经过完成以下使命来获取关键词字数统计、文本情感正负向和谈论主题模型:

  • 断定语料是否为目标言语
  • 别离并剖析语猜中的 emoji
  • 依据言语类型(中文或英文)对语料进行整理
  • 运用言语模型进行分词,并核算词频
  • 运用言语模型进行情感剖析
  • 主题模型进行文本分类

1.整理非目标言语

因为猫途鹰是全球性网站,许多谈论会搀杂多种言语。在本项目中咱们剖析的重点是中文和英文谈论,这意味着咱们需求挑选掉非目标言语的谈论。为了更全面的剖析,咱们也能够将一些运用人群较多的言语包括进来(如法语、西班牙语等),但每一种言语都需求相对应的剖析和模型,不行混为一谈。

这儿,咱们挑选的言语检测器为 LangID,是一个独立言语辨认库。它既能够在 Python 中运转,也能够在 Linux 环境中运转,是灵敏度较高的言语检测器之一。以中文谈论为例,咱们按句为单位勘探句子的言语,若该句子不是中文,咱们将其移出文本。但因为无法将别种言语依照中文的逻辑来分词,关于在同一句子中混用别种言语的词语,咱们仍旧按中文处理。英文谈论的处理也是相同的逻辑。

def filter_text_lan(s,lan):
   if lan == 'zh':
       s_lst = re.split('。',s.replace('.','。'))
   else:
       s_lst = s.split('. ')
   s_new = ''
   for sentence in s_lst:
       s_lan = langid.classify(sentence)
       if s_lan[0] == lan:
           append_s = sentence+'. '
           s_new += append_s
   return s_new

为了更全面的文本剖析,咱们将标题与谈论内容进行兼并,中心以句号离隔,并对 Pandas DataFrame 中代表兼并文本内容的列运转 filter_text_lan() 方程。

中文谈论:

df['comment_text'] = df['title'] + '。' + df['content']
df['text_zh_filtered'] = df['comment_text'].apply(lambda x: filter_text_lan(x,"zh"))

英文谈论:

df['comment_text'] = df['title'] + '. ' + df['content']
df['text_en_filtered'] = df['comment_text'].apply(lambda x: filter_text_lan(x,"en"))

2.处理 emoji 并整理语猜中不需求的内容

Emoji 作为深受全球喜爱的表情符号,在本项意图语猜中也频繁出现。为了后续分词等建模过程,咱们有必要先将 emoji 从文本中别离出来,效果传送至数据库中。

运用以下方程将 emoji 从文本中提取出来,并去重。

def extract_emojies(s):
   emoji_list = []
   for c in s:
       if c in emoji.EMOJI_DATA:
           emoji_list.append(c)
   return list(dict.fromkeys(emoji_list))

以中文为例:

emojis_series = df['text_zh_filtered'].apply(extract_emojies)

这样咱们就得到了语猜中一切的 emoji。接下来咱们的目标是,将 emoji 的出现与具体某一个谈论联系起来,并针对 emoji 统计词频。

mlb = MultiLabelBinarizer()
emojis_series_transformed = pd.DataFrame(mlb.fit_transform(emojis_series),
                                          columns=mlb.classes_,
                                          index=emojis_series.index)

然后将其与语料数据兼并:

df_transformed = df.join(emojis_series_transformed)

这儿,更新后的数据会将一切出现的 emoji 作为列,假如谈论中出现了对应的 emoji,则记载数值为1,反之为0。数据在经过处理后的结构大致如下:

df_transformed.columns

中文谈论数据:

数据科学在文本分析中的应用 :中英文 NLP(下)

英文谈论数据:

数据科学在文本分析中的应用 :中英文 NLP(下)

在获取 emoji 信息之后,咱们能够运用 demoji 库将 emoji 从谈论语猜中删去。

def remove_emoji(s):
   s = demoji.replace(s,'')
   return s.strip()

在中文谈论语猜中,因为网页结构的差异,过长的文本会被折叠,而且 Selenium 在抓取谈论内容时无法获取被折叠的内容,会将“阅览更多”的文本一同抓取下来。国际版网站与中文版网站结构的区别是,尽管在视觉上显现的谈论格局大致相同,但在网页结构中谈论文本并不会被折叠。为了应对中文语料的特殊情况,咱们对上述方程进行了必定的变形:

def remove_zh_chars(s):
   if "阅览更多" in s:
       s = s.replace("\n阅览更多。", '')
   s = demoji.replace(s,'')
   return s.strip()

咱们在谈论变量上运转该程序:

英文谈论:

df_transformed['text_en_cleaned'] = df_transformed['text_en_filtered'].apply(remove_emoji)

中文谈论:

df_transformed['text_zh_cleaned'] = df_transformed['text_zh_filtered'].apply(remove_zh_chars)

3.情感剖析(中文文本)

主流的中文文本情感剖析模型有两种:运用经典机器学习贝叶斯算法的 SnowNLP 和运用 RNN 的 Cemotion。SnowNLP 和 Cemotion 回来值都在0-1之间。SnowNLP 回来值越接近0则越负向,越接近1则越正向;而 Cemotion 回来的是文本是正向的概率。

在本项目中,咱们将测验这两种模型,依据效果择优挑选。人工标示往往需求消耗许多时刻,因此咱们决议随机选取20条谈论,人工标示正负向。

random.seed(1024)
sample_text = sample(list(df_transformed['text_zh_cleaned']),k=20)

在打印了样本谈论后,将对应的情感倾向人工打标。正向为1,负向为0。

marked_sentiment = [1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

两种算法的效果都介于0和1之间,咱们需求拟定判别正负向的规范:都以0.5为界,效果大于0.5为正向(回来数值1),小于等于0.5为负向(回来数值0)。

像之前处理文本数据一样,这儿咱们先编写处理单个字符串的方程,运用 map 将该方程使用在取样的20条文本上。

# SnowNLP
def get_snownlp_senti(s):
   snownlp_obj = SnowNLP(s)
   s_score = snownlp_obj.sentiments
   if s_score > 0.5:
       return 1
   else:
       return 0
# Cemotion
c = Cemotion()
def get_cemotion_senti(s,model=c):
   score = model.predict(s)
   if score > 0.5:
       return 1
   else:
       return 0
snownlp_result = list(map(get_snownlp_senti, sample_text))
cemotion_result = list(map(get_cemotion_senti, sample_text))

将效果进行比较,查看准确率。

数据科学在文本分析中的应用 :中英文 NLP(下)

能够看到,SnowNLP 与 Cemotion 准确率大致相同。因为谈论大多都是好评,Cemotion 的一切猜测效果都为正向。在人工标示的过程中,咱们会对谈论进行比较,把相对而言较为负向的谈论标为负向,所以 Cemotion 站在完全客观的视点将这些谈论标为正向也能够了解。

SnowNLP 标出了以下文字为负向心情:

数据科学在文本分析中的应用 :中英文 NLP(下)

这条谈论全体是偏正向的,SnowNLP 的算规律认为其是负向。

在测验过程中,咱们发现 SnowNLP 在核算速度上更快,但准确度有限;Cemotion 尽管速度慢,但精准度更高。因此,结合咱们的数据量,在本项目中咱们将保存 Cemotion 的效果。留意,两种算法都包括了分词等功用,只需输入文本信息即可获得情感倾向效果。

中文谈论情感倾向核算方程:

def get_sentiment_score(data, text_col="text_zh_cleaned"):
   data_cp = data.copy()
   text_series = data_cp[text_col]
   ## SnowNLP
   #snownlp_result = list(map(get_snownlp_senti, text_series.to_list()))
   #data_cp['snownlp_senti'] = snownlp_result
   ## Cemotion
   cemotion_result = list(map(get_cemotion_senti, text_series.to_list()))
   data_cp['cemotion_senti'] = cemotion_result
   return data_cp

咱们将语料数据传递给 get_sentiment_score() 对每条谈论的情感倾向进行核算。留意,这儿方程回来的是承继了原数据的新 Pandas DataFrame,英文则是将该信息加入了原 Pandas DataFrame 中;这么做的原因是在以后运用相似的功用时,能够保存 SnowNLP 的效果。中文谈论后续运用的 Pandas DataFrame 名为 df_senti,英文为 df_transformed。

数据科学在文本分析中的应用 :中英文 NLP(下)

最后,在1710条中文谈论中,负向情感倾向的谈论有117条(占比7.19%),正向情感的有1593条(占比92.81%)。

4.情感剖析(英文文本)

关于英文谈论的情感剖析,也是相似的操作,但咱们挑选了更适合英文语料的工具 TextBlob(NLTK 的包装器形式)。TextBlob 以0为界,负值为负向,正值为正向。

def get_en_senti(s_text):
   score = TextBlob(s_text).sentiment[0]
   if score > 0:
       return 1
   else:
       return 0

将该方程在语料变量上运转:

df_transformed['blob_senti'] = df_transformed['text_en_cleaned'].apply(get_en_senti)

在得到阶段性效果后,咱们将效果写进数据库,便于后续的可视化剖析运用。留意,在 Jupyter 环境中 emoji 的显现没有问题,但在数据库环境中并非如此。稳妥起见,咱们需求将 emoji 转换为字符串,再将相应效果写进数据库。

中文谈论数据:

# 挑选需求的变量
cols_to_db = ['user_id', 'location', 'trip_type', 'comment_date', 'comment_year', 'comment_month',
             'rating', 'if_pics_attached', 'data_ts','text_zh_cleaned','cemotion_senti',
             '☔', '⛈', '', '', '', '',
             '', '', '', '','', '', '', '', '', '', '', '', '']
# 将emoji转化为英文字符串
cols_to_db_transformed = list(map(emoji.demojize,cols_to_db))
# 选取需求的数据,并更新变量称号
df_to_db = df_senti[cols_to_db]
df_to_db.columns = cols_to_db_transformed
# 将数据写进数据库
df_to_db.to_sql("上海_上海_外滩_cleaned_senti_ZH", engine, if_exists="replace", index=False)

英文谈论数据:

cols_to_db = ['user_id', 'location_city', 'location_country', 'trip_type', 'comment_date',
             'comment_year', 'comment_month',
             'rating', 'if_pics_attached', 'data_ts','text_en_cleaned', 'blob_senti',
             '☺', '♥', '❤', '⭐', '', '', '','', '', '', '']
cols_to_db_transformed = list(map(emoji.demojize,cols_to_db))
df_to_db = df_transformed[cols_to_db]
df_to_db.columns = cols_to_db_transformed
df_to_db.to_sql("Shanghai_Shanghai_The Bund (Wai Tan)_cleaned_senti_EN", engine, if_exists="replace", index=False)

5.根据情感倾向的 emoji 剖析

咱们以情感心情为组,统计 emoji 出现的频率。“emoji_count_cols” 为打印 Pandas DataFrame 变量后从中提取的 emoji 和情感倾向变量。

中文谈论:

# 摘取需求的变量
emoji_count_cols = ['☔', '⛈', '', '', '', '', '', '', '', '',
                   '', '', '', '', '', '', '', '', '','cemotion_senti']
# 提取心情倾向
emoji_only_df = df_senti[emoji_count_cols]
# 将emoji转换为英文字符串
emoji_only_df.columns = list(map(emoji.demojize,emoji_count_cols))
emoji_counts = (emoji_only_df
               .groupby('cemotion_senti').sum().transpose()
               .reset_index()
               .rename_axis(None, axis=1)
               .rename(columns={'index':'emoji',0:'senti_0_count',1:'senti_1_count'})
               .sort_values(by=['senti_0_count','senti_1_count'],ascending=False)
              )
emoji_counts

数据科学在文本分析中的应用 :中英文 NLP(下)

英文谈论:

emoji_count_cols = ['☺', '♥', '❤', '⭐', '', '', '','', '', '', '','blob_senti']
emoji_only_df = df_transformed[emoji_count_cols]
emoji_only_df.columns = list(map(emoji.demojize,emoji_count_cols))
emoji_counts = (emoji_only_df
               .groupby('blob_senti').sum().transpose()
               .reset_index()
               .rename_axis(None, axis=1)
               .rename(columns={'index':'emoji',0:'senti_0_count',1:'senti_1_count'})
               .sort_values(by=['senti_0_count','senti_1_count'],ascending=False)
              )
emoji_counts

数据科学在文本分析中的应用 :中英文 NLP(下)

将 emoji 的词频效果写进数据库,以便后续剖析。

中文 emoji 归纳表:

emoji_counts.to_sql("上海_上海_外滩_emoji_count_ZH", engine, if_exists="replace", index=False)

英文 emoji 归纳表:

emoji_counts.to_sql("Shanghai_Shanghai_The Bund (Wai Tan)_emoji_count_EN", engine, if_exists="replace", index=False)

6.分词(中文文本)

在本项目中,咱们建模的首要目标是情感剖析与主题剖析。关于模型而言,文字并非有效的输入,需求将文本信息数字化,并将数字化效果传递给模型,然后输出效果。在达成建模目标之前,咱们需求对文本进行分词,并对词性进行标示。留意,各种言语有不同的分词办法,中文分词需求依据单词和前后句子判别,而英文分词多数以空白格为界。咱们需求依据言语品种来挑选不同的分词办法,具体过程总结如下:

  • 删去空白格和标点符号
  • 运用言语对应的算法将文本字符串分词
  • 查看分词效果,删去中止词

中文谈论部分运用的 Python 库为 jieba,是最受欢迎的中文分词组件之一,包括运用 Viterbi 算法新词学习的才能。它具有多种分词形式,其间 paddle 形式利用了 PaddlePaddle 深度学习结构,练习序列标示(双向 GRU)网络模型完成分词。

为了判别哪类分词办法更适合,咱们选取数据中的前5条谈论作为样本进行测验:

# 选取谈论
test_list = df_transformed.loc[:5,'text_zh_cleaned']
# 敞开paddle形式
paddle.enable_static()
jieba.enable_paddle()
# 打印分词效果
for s in test_list:
   print(s)
   seg_list = jieba.cut(s,use_paddle=True) # 运用paddle形式
   print("Paddle Mode: " + '/ '.join(list(seg_list)))
   seg_list = jieba.cut(s, cut_all=True)
   print("Full Mode: " + "/ ".join(seg_list)) # 全形式
   seg_list = jieba.cut(s, cut_all=False)
   print("Default Mode: " + "/ ".join(seg_list)) # 准确形式
   seg_list = jieba.cut_for_search(s) # 查找引擎形式
   print("Search Mode: " + "/ ".join(seg_list))

其间第4条谈论的打印效果为:

十点左右开端人比较少。感觉不管作为游客仍是居民,在这儿漫步都是十分享用的。 黄浦江边的风很舒畅,江对面灯火之下便是富贵的上海,很浪漫。
Paddle Mode: 十点/ 左右/ 开端/ 人/ 比较/ 少/ 。/ 感觉/ 不/ 论/ 作为/ 游客/ 仍是/ 居民/ ,/ 在这儿/ 漫步/ 都是/ 十分/ 享用/ 的/ 。 / 黄浦/ 江边/ 的/ 风/ 很舒畅/ ,江/ 对面/ 灯火/ 之/ 下/ 便是/ 富贵/ 的/ 上海/ ,/ 很/ 浪漫/ 。
Full Mode: 十点/ 左右/ 开端/ 人/ 比较/ 较少/ 。/ 感觉/ 不管/ 作为/ 游客/ 仍是/ 居民/ ,/ 在/ 这儿/ 漫步/ 都/ 是非/ 十分/ 享用/ 的/ 。/ / / 黄浦/ 黄浦江/ 浦江/ 江边/ 的/ 风/ 很/ 舒畅/ ,/ 江/ 对面/ 灯火/ 之下/ 便是/ 富贵/ 的/ 上海/ ,/ 很/ 浪漫/ 。
Default Mode: 十点/ 左右/ 开端/ 人/ 比较/ 少/ 。/ 感觉/ 不管/ 作为/ 游客/ 仍是/ 居民/ ,/ 在/ 这儿/ 漫步/ 都/ 是/ 十分/ 享用/ 的/ 。/ / 黄浦江/ 边/ 的/ 风/ 很/ 舒畅/ ,/ 江/ 对面/ 灯火/ 之下/ 便是/ 富贵/ 的/ 上海/ ,/ 很/ 浪漫/ 。
Search Mode: 十点/ 左右/ 开端/ 人/ 比较/ 少/ 。/ 感觉/ 不管/ 作为/ 游客/ 仍是/ 居民/ ,/ 在/ 这儿/ 漫步/ 都/ 是/ 十分/ 享用/ 的/ 。/ / 黄浦/ 浦江/ 黄浦江/ 边/ 的/ 风/ 很/ 舒畅/ ,/ 江/ 对面/ 灯火/ 之下/ 便是/ 富贵/ 的/ 上海/ ,/ 很/ 浪漫/ 。

第5条谈论的打印效果为:

外滩夜景yyds。超级美的浦江夜景三件套~今日爱情了 晚上吃过晚饭,去江边走一走,散散心,消消食,真的感觉超级美好~外滩估量是每个人来上海必打卡的项目之一了。
Paddle Mode: 外滩/ 夜景/ yyds。/ 超级/ 美/ 的/ 浦江/ 夜景/ 三件套/ ~/ 今日/ 爱情/ 了/ / 晚上/ 吃/ 过/ 晚饭/ ,/ 去/ 江边/ 走一走/ ,散散心,消消食,/ 真/ 的/ 感觉/ 超级美好~/ 外滩/ 估量/ 是/ 每个人/ 来/ 上海/ 必/ 打卡/ 的/ 项目/ 之/ 一/ 了/ 。
Full Mode: 外滩/ 夜景/ yyds/ 。/ 超级/ 美的/ 浦江/ 夜景/ 三件/ 三件套/ 件套/ ~/ 今日/ 爱情/ 了/ / / / 晚上/ 吃/ 过晚/ 晚饭/ ,/ 去/ 江边/ 走/ 一/ 走/ ,/ 散散/ 散散心/ 散心/ ,/ 消消/ 消食/ ,/ 真的/ 感觉/ 超级/ 美好/ ~/ 外滩/ 估量/ 是/ 每个/ 个人/ 来/ 上海/ 必/ 打卡/ 的/ 项目/ 之一/ 了/ 。
Default Mode: 外滩/ 夜景/ yyds/ 。/ 超级/ 美的/ 浦江/ 夜景/ 三件套/ ~/ 今日/ 爱情/ 了/ / 晚上/ 吃/ 过/ 晚饭/ ,/ 去/ 江边/ 走/ 一/ 走/ ,/ 散散心/ ,/ 消/ 消食/ ,/ 真的/ 感觉/ 超级/ 美好/ ~/ 外滩/ 估量/ 是/ 每个/ 人来/ 上海/ 必/ 打卡/ 的/ 项目/ 之一/ 了/ 。
Search Mode: 外滩/ 夜景/ yyds/ 。/ 超级/ 美的/ 浦江/ 夜景/ 三件/ 件套/ 三件套/ ~/ 今日/ 爱情/ 了/ / 晚上/ 吃/ 过/ 晚饭/ ,/ 去/ 江边/ 走/ 一/ 走/ ,/ 散散/ 散心/ 散散心/ ,/ 消/ 消食/ ,/ 真的/ 感觉/ 超级/ 美好/ ~/ 外滩/ 估量/ 是/ 每个/ 人来/ 上海/ 必/ 打卡/ 的/ 项目/ 之一/ 了/ 。

咱们选取的这两条谈论中都提及了一些活动,但办法不同。第4条谈论的原句是“感觉不管作为游客仍是居民,在这儿漫步都是十分享用的”,直接运用了“漫步”这个动词;而在第5条谈论的原句“去江边走一走,散散心”中,“散心”这个动词并不是单独提及的。在Paddle和精准形式中,算法一般会把相似“散散心”这种动词辨认为一个词,必定程度上会影响咱们对关键词的区分。但在辨认专有名词时,paddle 形式会保存一些例如“和平饭店”、“万达瑞华酒店”这类专有名词,而其他形式(特别是查找形式)则会将长句进一步拆分。

归纳考量往后,咱们决议运用精准形式来分词。除此之外,咱们会把没有研究含义的中止词从分词效果中删去。中文 NLP 有多种中止词表可供挑选,在这儿咱们运用的是哈尔滨工业大学开发的中止词表。

# 读取中止词
with open('hit_stopwords.txt','r') as f:
   stopwords = [line.strip() for line in f]
# 将上海、外滩这类在语猜中频繁出现但是并不需求的词加入中止词表
stopwords = stopwords+['上海','外滩']   
def text_tokenizer_zh(s):
   # 删去空白格
   s = s.strip() 
   # 删去标点符号
   s = re.sub(r"[0-9\s+\.\!\/_,$%^*()?;;:-【】+\"\']+|[+——!,;:。?、~@#¥%……&*()~]+", "", s)
   seg_list = jieba.posseg.cut(s)
   cut_list = [(x.word,x.flag) for x in seg_list if x.word not in stopwords]
   return cut_list

运转上述方程:

zh_text_tokenized = df_senti['text_zh_cleaned'].apply(text_tokenizer_zh)
df_senti['text_zh_tokenized'] = zh_text_tokenized

7.分词(英文文本)

英文 NLP 中最抢先的渠道之一便是 NLTK(Natural Language Toolkit)。NLTK 具有50个语料库和词汇材料,开发了多种如分词、情感剖析、标记、语义推理等言语处理功用。因此在处理英文谈论时,咱们挑选 NLTK 来处理英文语料。在分词的过程中,各个词会同步进行词性标示。

在运用 NLTK 前,咱们需求下载以下数据和算法:

# 下载NLTK算法资源
nltk.download('punkt')
nltk.download('averaged_perceptron_tagger')
nltk.download('stopwords')
nltk.download('wordnet')
nltk.download('omw-1.4')

有了相关的算法和数据后,咱们就能够运用 NLTK 库中的 pos_tag 方程进行英文分词。相同的,咱们会从分词效果中删去中止词,这儿运用的中止词资源是 NLTK 自带的英文中止词表。

# 从NLTK中读取英文中止词资源
stop_words = stopwords.words('english') 
stop_words+=["shanghai",'bund']
wl = WordNetLemmatizer() 
def text_tokenizer_en(s):
   # remove blank space
   s = s.strip()  
   tags = pos_tag(word_tokenize(s))
   tokenized_list = []
   for word, tag in tags:
       tag_lemma = tag[0].lower()
       wntag = tag_lemma if tag_lemma in ['a', 'r', 'n', 'v'] else None
       if word.lower() not in stop_words and word.isalpha():
           if wntag is None:
               lemma_word = wl.lemmatize(word.lower())
           else:
               lemma_word = wl.lemmatize(word.lower(),wntag)
           tokenized_list.append((lemma_word,tag))  
   return tokenized_list

在英文语料数据上运转该方程:

en_text_tokenized = df_transformed['text_en_cleaned'].apply(text_tokenizer_en)
df_transformed['text_en_tokenized'] = en_text_tokenized

8.词性词频剖析

在中文分词的基础上,咱们还做了词性的标示,以名词为例,jieba 会将名词进一步细分为一般名词、地名、人名和其他专名。咱们依照以下办法将 jieba 分词后的词语归类为名词、动词和形容词三类:

  • 名词(n):n,nr,ns,nt,nz
  • 动词(v):v,vn
  • 形容词(a):a

和中文谈论相似,咱们依照以下办法将nltk分词后的英文单词做了如下归类:

  • 名词(n):NN,NNS,NNP,NNPS,FW
  • 动词(v):VB,VBD,VBG,VBN
  • 形容词(a):JJ,JJR,JJS

如下所示,分词往后,每一段谈论都转化为一个元组列表(list of tuples),每个元组格局为(词,词性)。

中文分词效果展现:

数据科学在文本分析中的应用 :中英文 NLP(下)

英文分词效果展现:

数据科学在文本分析中的应用 :中英文 NLP(下)

以下方程能够将上述格局的分词数据经过词性进行挑选,并核算每个词对应的词频,中英文分词数据通用。这儿咱们运用的小技巧是组合运用 Python 中的 itertools 库和 collection 库,将表单 list 中的表单元素合为单个表单,并运用 collection 中的 counter 核算各个元素的频率。

pos_map_zh = {'n':['n', 'nr', 'ns', 'nt', 'nz'], 'v':['v','vn'], 'a':['a']}
pos_map_en = {'n':['NN','NNS','NNP','NNPS','FW'], 'v':['VB','VBD','VBG','VBN'],
             'a':['JJ','JJR','JJS']}
def get_word_count(token_series, pos_flg, lan):
   # 将表单list中的表单元素合为单个表单
   word_list = list(itertools.chain.from_iterable(token_series))
   if lan.upper() == 'ZH':
       pos_lst = pos_map_zh[pos_flg]
   else:
       pos_lst = pos_map_en[pos_flg]
   word_list_filtered = [x[0] for x in word_list if x[1] in pos_lst]
   # 核算各个元素的频率
   counts = Counter(word_list_filtered)
   data_items = counts.items()
   data_list = list(data_items)
   # 将效果转换为DataFrame输出
   word_count_df = pd.DataFrame(data_list)
   word_count_df.rename(columns = {0:'word', 1:'frequency'}, inplace = True)
   word_count_df['pos'] = pos_flg
   return word_count_df

输入一个字符串,该方程就会依据输入的词性进行挑选,并核算出相应的词频。以英文为例,咱们期望在语料字符串中挑选出名词并进行词频核算,效果展现如下:

数据科学在文本分析中的应用 :中英文 NLP(下)

有了 get_word_count(),咱们就能够依据从多个维度对词语进行词频统计,分别是:心情倾向、词性、谈论年份、谈论月份。

def word_count_grouped(data, token_col, lan):
   data_copy = data.copy()
   # 运用谈论言语心情倾向相对应的变量名
   if lan.upper() == 'ZH':
       senti_col = 'cemotion_senti'
       pos_map = pos_map_zh
   else:
       senti_col = 'blob_senti'
       pos_map = pos_map_en
   # 核算心情倾向,谈论年份和月份变量各自去重后的值
   senti_values = data[senti_col].unique()
   year_values = data['comment_date'].dt.year.unique()
   month_values = data['comment_date'].dt.month.unique()
   result_count_df = pd.DataFrame()
   # 依据特定的心情倾向,谈论年份和月份值,核算这类谈论的词频
   for pos_flg in pos_map.keys():
       for senti in senti_values:
           for y in year_values:
               for m in month_values:
                   data_filtered = data[(data[senti_col]==senti)&(data['comment_year']==y)&(data['comment_month']==m)]
                   if data_filtered.shape[0] > 0:
                       count_df = get_word_count(data_filtered[token_col], pos_flg, lan)
                       count_df[senti_col] = senti
                       count_df['comment_year'] = y
                       count_df['comment_month'] = m
                       result_count_df = pd.concat([result_count_df, count_df])
   return result_count_df.reset_index(drop=True)

在中文分词效果上运转,并将效果写进数据库:

word_count_df = word_count_grouped(df_senti,'text_zh_tokenized','zh')
word_count_df.to_sql("上海_上海_外滩_word_count_ZH", engine, if_exists="replace", index=False)

中文词频效果展现:

数据科学在文本分析中的应用 :中英文 NLP(下)

在英文分词效果上运转:

word_count_df = word_count_grouped(df_transformed,'text_en_tokenized','EN')
word_count_df.to_sql("Shanghai_Shanghai_The Bund (Wai Tan)_word_count_EN", engine, if_exists="replace", index=False)

英文词频效果展现:

数据科学在文本分析中的应用 :中英文 NLP(下)

9.关键词剖析

Jieba 中包括两种更高阶的用来核算关键词的算法:TF-IDF 和 TextRank。其间 TF-IDF 作为词袋模型(Bag of Word)也经常被用来作为将文字内容数字化的算法之一。因为这两种算法自带整理模块,咱们直接运用了原文本而并非去除了停用词的语料。

s_concat_list = ''.join(df_senti['text_zh_cleaned'].to_list())

根据TF-IDF的关键词:

数据科学在文本分析中的应用 :中英文 NLP(下)

根据TextRank的关键词:

数据科学在文本分析中的应用 :中英文 NLP(下)

两种算法的效果在排序上略有不同。

10.词云展现

为了进一步了解游客们对上海外滩的谈论内容,咱们将中英文语猜中的名词、动词和形容词分别制作了词频词云,并将词云效果保存。这儿咱们运用的库是 WordCloud。因为 WordCloud 无法区分中文,词云会出现乱码的情况。咱们需求手动上传中文字体 .tff 文件并传递给 WordCloud,这儿咱们运用的是开源的阿里巴巴普惠体。

def get_word_cloud_pos(count_df,font_pth, lan):
   pos_values = count_df['pos'].unique()
   fig = plt.figure(figsize=(30,25))
   for i,pos_tag in enumerate(pos_values):
       word_count_sum = count_df[count_df['pos']==pos_tag].groupby(['word'])[['frequency']].sum().reset_index()
       word_count_dict = word_count_sum.set_index('word').to_dict()['frequency']
       wc = WordCloud(width=1000, height=800,background_color = 'white',font_path = font_pth).generate_from_frequencies(word_count_dict)
       ax = fig.add_subplot(1,len(pos_values),i+1)
       ax.imshow(wc)
       ax.title.set_text("Word Count for POS: "+pos_tag)
       ax.axis('off')
   plt.savefig('word_cloud_'+lan+'.png')
   return

运转该方程获得中文词云:

get_word_cloud_pos(word_count_df,'ALIBABA-PUHUITI-REGULAR.TTF','ZH')

数据科学在文本分析中的应用 :中英文 NLP(下)

运转该方程获得英文词云:

get_word_cloud_pos(word_count_df,'ALIBABA-PUHUITI-REGULAR.TTF','EN')

数据科学在文本分析中的应用 :中英文 NLP(下)

能够看到,无论是中文仍是英文的语料,占比较高的词在含义上十分相近,两种言语的词云效果很相似。

11.主题模型文本分类

为了丰富文本剖析的层次,咱们还运用主题模型(Topic Modelling)对语料进行无监督学习,依据语义将相似的文本划为一组,对谈论进行分类。主题模型首要有两类:pLSA(Probabilistic Latent Semantic Analysis)和 LDA(Latent Dirichlet Allocation),LDA 是根据 pLSA 算法的延伸,使得模型能够适应新的文本。

留意,因为咱们事先并不知道文本分为几个品种,主题模型是一个无监督学习使命,咱们需求依据效果调整文本类别的数量。这儿,咱们运用了 Python 的 Genism 工具库来辨认中英文文本的语意主题。

def get_topics(data, topics_n, token_col):
   # 树立分词表
   l_words_list = [[word[0] for word in doc] for doc in data[token_col]]
   # 树立语料库
   word_dict = corpora.Dictionary(l_words_list)
   corpus = [word_dict.doc2bow(text) for text in l_words_list]
   # 树立模型
   lda_model = models.LdaMulticore(corpus=corpus,
                                   id2word=word_dict,
                                   num_topics=topics_n)
   # 打印文本分类效果
   topic_list_lda = lda_model.print_topics()
   # topic_list_lsi = lsi.print_topics(16)
   print("以LDA为分类器的"+str(topics_n)+"主题的单词散布为:\n")
   for topic in topic_list_lda:
       print(topic)

咱们能够尝试多个文本类别数量,看效果是否有价值,这部分十分依赖剖析者自身的判别,需求探讨文本类别数量的合理性。

中文文本类别数量中比较有含义是2类主题,LDA 效果如下:

数据科学在文本分析中的应用 :中英文 NLP(下)

能够看出,效果并没有太大区别。事实上,在建模过程中,许多模型的表现并不会像人们预期的一样好。不过由此也能够看出,基本上中文谈论并没有杰出的类别,游客基本以旅行景象和修建为主,而且旅行时刻大多为晚上。

英文文本类别数量中比较有含义的是3类主题,LDA 效果如下:

数据科学在文本分析中的应用 :中英文 NLP(下)

无论是情感剖析仍是文本分类,本质上都是经过将文本转化为数字,一般再进行监督学习。数字化文本的办法大致有三类,它们分别是本项目中运用的以词频为基础的词袋模型(Bag of Word)、独热编码(One Hot Encoding)和文本向量化(Word2Vec);词袋模型中最富盛名的是 TF-IDF。这类使命都能够经过人工标示将分类效果传递给模型(如深度学习等),再经过练习效果挑选适宜的模型。这样的由用户自行练习的模型会更贴近项目需求,尽管开发周期长,但效果更精准。但在大数据时代,人工标示需求消耗许多的时刻和资金,这就诞生了许多比如 Cemotion 这样预先经历过许多文本练习的模型,供各类文本剖析使命运用,大大降低了时刻本钱和运用门槛。

至此,咱们就完成了对中英文 NLP 建模部分的介绍。文本剖析与建模基本都围绕着词频和分类这两块内容打开,核心是经过“数字”来出现大批量文本中的可用信息。而跟着算法的发展,以神经网络为主的例如 transformer 这类言语模型成为了大热的话题,模型的用途从开始批量处理和剖析文本数据,到现如今的虚拟客服、ChatGPT 等代替人工的使用,数据科学正在逐步融入人们的日常生活。假如咱们对神经网络在言语上的使用感兴趣,请继续重视 Data Science Lab 的后续博文。

参考材料:

  • 戴斌 | 新年旅行商场高开 全年旅行经济稳增
  • 西湖景区新年招待游客292.86万人次
  • Scrapy Vs Selenium Vs Beautiful Soup for Web Scraping
  • Extract Emojis from Python Strings and Chart Frequency using Spacy, Pandas, and Plotly
  • Topic Modeling with LSA, PLSA, LDA & lda2Vec