この記事は,NTTドコモアドベントカレンダー第11日目の記事になります。
こんな人に読んでほしい
- 口コミやツイートの分析をしている人
- 顔文字・絵文字・URLを抽出するツールを探している人
- 自然言語処理に興味がある人
※ 最後の付録で実装したソースコードを公開してます!
1. はじめに
自然言語処理にとって前処理は非常に重要です。
特に、商品の口コミやツイートは顔文字やURLなどのノイズが多く、前処理しないままでは思い通りの分析ができません😇
そこで本記事では、SNSテキストから顔文字・絵文字・URLを抽出して削除/置換するための前処理方法について紹介したいと思います。
2. 必要なもの
ツール
-
nagisa
- 顔文字・URLの検出に使います。日本語テキスト用の形態素解析ツールです。
- 参考記事: nagisa: RNNによる日本語単語分割・品詞タグ付けツール
-
emoji
- 絵文字の検出に使います。
- 参考記事: pythonで絵文字を駆逐する
インストール方法
$ pip install nagisa emoji
データ
抽出対象のSNSテキストデータです。ご自身で収集した口コミやツイートをご用意下さい。
もし手元に無い場合は、MTNTデータなどを使って試しましょう。
-
MTNT: Machine Translation of Noisy Text
- MTNTデータセットは、Redditという投稿型のソーシャルサイトの書き込みを収集したものです(日本の2ちゃんねるのような掲示板サイトに近いです)。
- スラングや文法誤り、顔文字・絵文字などのノイズを多く含むSNSテキストの機械翻訳の研究用に無償公開されています。
3. 実践: SNSテキストを前処理してみよう
それでは、実際にSNSテキストから顔文字・絵文字・URLを抽出してみましょう。
3.1 方針
顔文字・URLの抽出はnagisa、絵文字の抽出はemojiを使います。
3.2 顔文字の抽出方法
nagisa
は日本語テキスト用の形態素解析ツールですが、
うまく使いこなせば顔文字やURLを抽出することができます。
こちらの記事でも言及されている通り、nagisaでは顔文字やURLを1つの単語として単語分割することができます。
しかし、\(^o^)/
などの手を含む顔文字は1つの単語として分割することは難しいようです。
\/補助記号 (^o^)/補助記号 //補助記号
のように、3つの単語に分かれてしまいます。
nagisaの解析結果
ですが、うまく処理すれば、このような顔文字も抽出することができます。
仕組みは単純で、顔文字の手を事前に定義して、顔文字の周辺から手を一緒に抽出します。
import nagisa
import unicodedata
def extract_kaomoji(text):
""" 与えられたテキストから抽出した顔文字リストを返却する。
→ \(^o^)/, m(_ _)m などの 手を含む顔文字があれば、それも抽出する
"""
results = nagisa.extract(text, extract_postags=['補助記号'])
words = results.words
kaomoji_words = []
kaomoji_idx = [i for i, w in enumerate(words) if len(w) >= KAOMOJI_LEN]
kaomoji_hands = ['ノ', 'ヽ', '∑', 'm', 'O', 'o', '┐', '/', '\\', '┌']
# 顔文字と手を検索
for i in kaomoji_idx:
kaomoji = words[i] # 顔文字列
try:
# 顔文字の左手
if words[i-1] in kaomoji_hands and 0 < i:
kaomoji = words[i-1] + kaomoji
# 顔文字の右手
if words[i+1] in kaomoji_hands:
kaomoji = kaomoji + words[i+1]
except IndexError:
pass
finally:
kaomoji_words.append(kaomoji)
return kaomoji_words
text = "今日は渋谷スクランブルスクエアに行ってきた\(^o^)/ 夜景🏙サイコー❗️ https://hogehogehogehoge.jpg"
text = unicodedata.normalize('NFKC', text) # NFKC正規化
print(extract_kaomoji(text))
# => ['\\(^o^)/']
text = "ごめんなさいm(-_-)m"
text = unicodedata.normalize('NFKC', text) # NFKC正規化
print(extract_kaomoji(text))
# => ['m(-_-)m']
これで、テキストから顔文字を抽出することができました。
抽出結果
今日は渋谷スクランブルスクエアに行ってきた\(^o^)/ 夜景🏙サイコー❗️ https://hogehogehogehoge.jpg
顔文字: \(^o^)/
ごめんなさいm(-_-)m
顔文字: m(-_-)m
3.3 URLの抽出
URLの抽出はシンプルです。
必要な品詞の単語だけを抽出する関数nagisa.extract
で必要な品詞タグにURL
を条件付けるだけで、URLを抽出することができます。
import nagisa
import unicodedata
def extract_url(words):
results = nagisa.extract(text, extract_postags=['URL'])
return results.words
text = "今日は渋谷スクランブルスクエアに行ってきた\(^o^)/ 夜景🏙サイコー❗️ https://hogehogehogehoge.jpg"
text = unicodedata.normalize('NFKC', text) # NFKC正規化
print(extract_url(text))
# => ['https://hogehogehogehoge.jpg']
抽出結果
今日は渋谷スクランブルスクエアに行ってきた\(^o^)/ 夜景🏙サイコー❗️ https://hogehogehogehoge.jpg
URL: https://hogehogehogehoge.jpg
3.4 絵文字の抽出
絵文字の抽出も簡単です。
絵文字はUnicodeで定義されているため、文字のUnicodeを確認してその文字が絵文字かどうかを判定します。
emoji
で絵文字のUnicodeリストを使うことができます。
import emoji
import nagisa
import unicodedata
def extract_emoji(words):
return [w for w in words if w in emoji.UNICODE_EMOJI]
text = "今日は渋谷スクランブルスクエアに行ってきた\(^o^)/ 夜景🏙サイコー❗️ https://hogehogehogehoge.jpg"
text = unicodedata.normalize('NFKC', text) # NFKC正規化
print(extract_emoji(text))
# => ['🏙', '❗']
text = "日本語のテキストから絵文字😉を抽出するよ❗"
text = unicodedata.normalize('NFKC', text) # NFKC正規化
print(extract_emoji(text))
# => ['😉', '❗']
抽出結果
今日は渋谷スクランブルスクエアに行ってきた\(^o^)/ 夜景🏙サイコー❗️ https://hogehogehogehoge.jpg
絵文字: 🏙, ❗
日本語のテキストから絵文字😉を抽出するよ❗
絵文字: 😉, ❗
4. おわりに
テキストから顔文字・絵文字・URLを抽出する前処理方法を紹介しました。
本記事で紹介した前処理(一部)は、今年ドコモとNTTが参加したWMT19のRobustness taskに投稿したシステムでも使っています。
論文でも前処理について書いていますので、ツイートや口コミの分析に取り組んでいる方のお役に立てれば幸いです。
最後に、本記事を書く際に参考にさせていただいた記事を紹介します。
テキスト前処理についてとても良くまとめられているので、ぜひ参考にしてみて下さい。
テキスト前処理に関する記事のまとめ
- 自然言語処理における前処理の種類とその威力
- Python3×日本語:自然言語処理の前処理まとめ
- 自然言語(前)処理
- 自然言語のpythonでの前処理のかんたん早見表(テキストクリーニング、分割、ストップワード、辞書の作成、数値化)
- Pythonを使って自然言語処理の前処理を行う
- 形態素解析前の日本語文書の前処理 (Python)
付録
本記事で実装したコード(全文)です。
ソースコード
import emoji
import nagisa
import unicodedata
KAOMOJI_PH = "<Kaomoji>"
URL_PH = "<URL>"
EMOJI_PH = "<Emoji>"
KAOMOJI_LEN = 5
def extract_kaomoji(text):
""" 与えられたテキストから抽出した顔文字リストを返却する。
→ \(^o^)/, m(_ _)m などの 手を含む顔文字があれば、それも抽出する
"""
results = nagisa.extract(text, extract_postags=['補助記号'])
words = results.words
kaomoji_words = []
kaomoji_idx = [i for i, w in enumerate(words) if len(w) >= KAOMOJI_LEN]
kaomoji_hands = ['ノ', 'ヽ', '∑', 'm', 'O', 'o', '┐', '/', '\\', '┌']
# 顔文字と手を検索
for i in kaomoji_idx:
kaomoji = words[i] # 顔文字列
try:
# 顔文字の左手
if words[i-1] in kaomoji_hands and 0 < i:
kaomoji = words[i-1] + kaomoji
# 顔文字の右手
if words[i+1] in kaomoji_hands:
kaomoji = kaomoji + words[i+1]
except IndexError:
pass
finally:
kaomoji_words.append(kaomoji)
return kaomoji_words
def extract_url(words):
results = nagisa.extract(text, extract_postags=['URL'])
return results.words
def extract_emoji(text):
results = nagisa.tagging(text) # 形態素解析
words = results.words
return [w for w in words if w in emoji.UNICODE_EMOJI]
def replace(text, target_list, PH):
for trg in target_list:
text = text.replace(trg, PH)
return text
def delete(text, target_list):
for trg in target_list:
text = text.replace(trg, "")
return text
text = "今日は渋谷スクランブルスクエアに行ってきた\(^o^)/ 夜景🏙サイコー❗️ https://hogehogehogehoge.jpg"
text = unicodedata.normalize('NFKC', text) # NFKC正規化
# 入力
print("対象テキスト: {}\n".format(text))
# 抽出
kaomoji_list = extract_kaomoji(text)
url_list = extract_url(text)
emoji_list = extract_emoji(text)
# 抽出結果
print("顔文字: {}".format(kaomoji_list))
print("URL: {}".format(url_list))
print("絵文字: {}\n".format(emoji_list))
# 削除
deleted_text = delete(text, kaomoji_list + url_list + emoji_list)
print("削除: {} \n".format(deleted_text))
# 置換
replaced_text = replace(text, kaomoji_list, KAOMOJI_PH)
replaced_text = replace(replaced_text, url_list, URL_PH)
replaced_text = replace(replaced_text, emoji_list, EMOJI_PH)
print("置換: {} \n".format(replaced_text))
出力例
対象テキスト: 今日は渋谷スクランブルスクエアに行ってきた\(^o^)/ 夜景🏙サイコー❗️ https://hogehogehogehoge.jpg
顔文字: ['\\(^o^)/']
URL: ['https://hogehogehogehoge.jpg']
絵文字: ['🏙', '❗']
削除: 今日は渋谷スクランブルスクエアに行ってきた 夜景サイコー️
置換: 今日は渋谷スクランブルスクエアに行ってきた<Kaomoji> 夜景<Emoji>サイコー<Emoji>️ <URL>